mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-22 04:26:23 +08:00
Merge remote-tracking branch 'refs/remotes/origin/feat/datacenter'
Conflicts: package.json packages/app/src/components/create-workspace/index.tsx packages/app/src/components/workspace-modal/index.tsx packages/app/src/components/workspace-modal/languageMenu.tsx packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx packages/app/src/components/workspace-slider-bar/index.tsx packages/app/src/pages/_app.tsx pnpm-lock.yaml
This commit is contained in:
@@ -46,7 +46,6 @@
|
||||
"jest": "^29.3.1",
|
||||
"lint-staged": "^13.1.0",
|
||||
"prettier": "^2.7.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "^4.9.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
import { styled } from '@/styles';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal';
|
||||
import { Button } from '@/ui/button';
|
||||
import { useState } from 'react';
|
||||
import Input from '@/ui/input';
|
||||
import { useTemporaryHelper } from '@/providers/temporary-helper-provider';
|
||||
import { KeyboardEvent } from 'react';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
interface ICloseParams {
|
||||
workspaceId?: string;
|
||||
}
|
||||
import { useWorkspaceHelper } from '@/hooks/use-workspace-helper';
|
||||
interface ModalProps {
|
||||
open: boolean;
|
||||
onClose: (opts: ICloseParams) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => {
|
||||
const [workspaceName, setWorkspaceName] = useState('');
|
||||
const { createWorkspace, setActiveWorkspace } = useTemporaryHelper();
|
||||
const handleCreateWorkspace = () => {
|
||||
const workspace = createWorkspace(workspaceName);
|
||||
onClose({ workspaceId: workspace.id });
|
||||
setActiveWorkspace(workspace);
|
||||
const { createWorkspace } = useWorkspaceHelper();
|
||||
const router = useRouter();
|
||||
const handleCreateWorkspace = async () => {
|
||||
const workspace = await createWorkspace(workspaceName);
|
||||
if (workspace && workspace.room) {
|
||||
router.replace(`/workspace/${workspace.room}`);
|
||||
onClose();
|
||||
} else {
|
||||
console.log('create error');
|
||||
}
|
||||
};
|
||||
const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.key === 'Enter') {
|
||||
@@ -39,7 +42,7 @@ export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => {
|
||||
top={6}
|
||||
right={6}
|
||||
onClick={() => {
|
||||
onClose({});
|
||||
onClose();
|
||||
}}
|
||||
/>
|
||||
</Header>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import type { Page, Workspace } from '@blocksuite/store';
|
||||
import '@blocksuite/blocks';
|
||||
import { EditorContainer } from '@blocksuite/editor';
|
||||
import exampleMarkdown from '@/templates/Welcome-to-AFFiNE-Alpha-v2.0.md';
|
||||
import { styled } from '@/styles';
|
||||
|
||||
const StyledEditorContainer = styled('div')(() => {
|
||||
return {
|
||||
height: 'calc(100vh - 60px)',
|
||||
padding: '0 32px',
|
||||
};
|
||||
});
|
||||
|
||||
type Props = {
|
||||
page: Page;
|
||||
workspace: Workspace;
|
||||
setEditor: (editor: EditorContainer) => void;
|
||||
};
|
||||
|
||||
export const Editor = ({ page, workspace, setEditor }: Props) => {
|
||||
const editorContainer = useRef<HTMLDivElement>(null);
|
||||
// const { currentWorkspace, currentPage, setEditor } = useAppState();
|
||||
useEffect(() => {
|
||||
const ret = () => {
|
||||
const node = editorContainer.current;
|
||||
while (node?.firstChild) {
|
||||
node.removeChild(node.firstChild);
|
||||
}
|
||||
};
|
||||
|
||||
const editor = new EditorContainer();
|
||||
editor.page = page;
|
||||
|
||||
editorContainer.current?.appendChild(editor);
|
||||
if (page.isEmpty) {
|
||||
const isFirstPage = workspace?.meta.pageMetas.length === 1;
|
||||
// Can not use useCurrentPageMeta to get new title, cause meta title will trigger rerender, but the second time can not remove title
|
||||
const { title: metaTitle } = page.meta;
|
||||
const title = metaTitle
|
||||
? metaTitle
|
||||
: isFirstPage
|
||||
? 'Welcome to AFFiNE Alpha "Abbey Wood"'
|
||||
: '';
|
||||
workspace?.setPageMeta(page.id, { title });
|
||||
|
||||
const pageId = page.addBlock({
|
||||
flavour: 'affine:page',
|
||||
title,
|
||||
});
|
||||
page.addBlock({ flavour: 'affine:surface' });
|
||||
const frameId = page.addBlock({ flavour: 'affine:frame' }, pageId);
|
||||
page.addBlock({ flavour: 'affine:frame' }, pageId);
|
||||
// If this is a first page in workspace, init an introduction markdown
|
||||
if (isFirstPage) {
|
||||
editor.clipboard.importMarkdown(exampleMarkdown, `${frameId}`);
|
||||
workspace.setPageMeta(page.id, { title });
|
||||
page.resetHistory();
|
||||
}
|
||||
page.resetHistory();
|
||||
}
|
||||
|
||||
setEditor(editor);
|
||||
document.title = page?.meta.title || 'Untitled';
|
||||
return ret;
|
||||
}, [workspace, page, setEditor]);
|
||||
|
||||
return <StyledEditorContainer ref={editorContainer} />;
|
||||
};
|
||||
|
||||
export default Editor;
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
StyledTitleWrapper,
|
||||
} from './styles';
|
||||
import { Content } from '@/ui/layout';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import EditorModeSwitch from '@/components/editor-mode-switch';
|
||||
import QuickSearchButton from './QuickSearchButton';
|
||||
import Header from './Header';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CloudUnsyncedIcon, CloudInsyncIcon } from '@blocksuite/icons';
|
||||
import { useModal } from '@/providers/GlobalModalProvider';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { IconButton } from '@/ui/button';
|
||||
|
||||
export const SyncUser = () => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Button } from '@/ui/button';
|
||||
import { Wrapper, Content } from '@/ui/layout';
|
||||
import Loading from '@/components/loading';
|
||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
// import { Tooltip } from '@/ui/tooltip';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { getDataCenter } from '@affine/datacenter';
|
||||
// import { getDataCenter } from '@affine/datacenter';
|
||||
import { styled } from '@/styles';
|
||||
import { Button } from '@/ui/button';
|
||||
import { useModal } from '@/providers/GlobalModalProvider';
|
||||
// import { useModal } from '@/providers/GlobalModalProvider';
|
||||
import { GoogleIcon, StayLogOutIcon } from './Icons';
|
||||
|
||||
export const GoogleLoginButton = () => {
|
||||
const { triggerLoginModal } = useModal();
|
||||
// const { triggerLoginModal } = useModal();
|
||||
return (
|
||||
<StyledGoogleButton
|
||||
onClick={() => {
|
||||
|
||||
@@ -20,7 +20,7 @@ import DateCell from '@/components/page-list/DateCell';
|
||||
import { IconButton } from '@/ui/button';
|
||||
import { Tooltip } from '@/ui/tooltip';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { toast } from '@/ui/toast';
|
||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||
import { useTheme } from '@/providers/ThemeProvider';
|
||||
|
||||
@@ -17,11 +17,10 @@ export const Input = (props: {
|
||||
const [isComposition, setIsComposition] = useState(false);
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const { currentWorkspaceId, workspacesMeta, currentWorkspace } =
|
||||
useAppState();
|
||||
const isPublic = workspacesMeta.find(
|
||||
const { currentWorkspaceId, workspaceList, currentWorkspace } = useAppState();
|
||||
const isPublish = workspaceList.find(
|
||||
meta => String(meta.id) === String(currentWorkspaceId)
|
||||
)?.public;
|
||||
)?.isPublish;
|
||||
useEffect(() => {
|
||||
inputRef.current?.addEventListener(
|
||||
'blur',
|
||||
@@ -80,7 +79,7 @@ export const Input = (props: {
|
||||
}
|
||||
}}
|
||||
placeholder={
|
||||
isPublic
|
||||
isPublish
|
||||
? `Search in ${currentWorkspace?.meta.name}`
|
||||
: 'Quick Search...'
|
||||
}
|
||||
|
||||
@@ -22,16 +22,14 @@ const isMac = () => {
|
||||
return getUaHelper().isMacOs;
|
||||
};
|
||||
export const QuickSearch = ({ open, onClose }: TransitionsModalProps) => {
|
||||
const { currentMetaWorkSpace } = useAppState();
|
||||
|
||||
const [query, setQuery] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [showCreatePage, setShowCreatePage] = useState(true);
|
||||
const { triggerQuickSearchModal } = useModal();
|
||||
const { currentWorkspaceId, workspacesMeta } = useAppState();
|
||||
|
||||
const currentWorkspace = workspacesMeta.find(
|
||||
meta => String(meta.id) === String(currentWorkspaceId)
|
||||
);
|
||||
const isPublic = currentWorkspace?.public;
|
||||
const isPublish = currentMetaWorkSpace?.isPublish;
|
||||
|
||||
// Add ‘⌘+K’ shortcut keys as switches
|
||||
useEffect(() => {
|
||||
@@ -98,7 +96,7 @@ export const QuickSearch = ({ open, onClose }: TransitionsModalProps) => {
|
||||
setShowCreatePage={setShowCreatePage}
|
||||
/>
|
||||
</StyledContent>
|
||||
{isPublic ? (
|
||||
{isPublish ? (
|
||||
<></>
|
||||
) : showCreatePage ? (
|
||||
<>
|
||||
|
||||
@@ -1,30 +1,49 @@
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { stringToColour } from '@/utils';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
interface IWorkspaceAvatar {
|
||||
size: number;
|
||||
name: string;
|
||||
avatar: string;
|
||||
}
|
||||
|
||||
export const WorkspaceAvatar = (props: IWorkspaceAvatar) => {
|
||||
const size = props.size || 20;
|
||||
const sizeStr = size + 'px';
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
width: sizeStr,
|
||||
height: sizeStr,
|
||||
border: '1px solid #fff',
|
||||
color: '#fff',
|
||||
fontSize: Math.ceil(0.5 * size) + 'px',
|
||||
background: stringToColour(props.name || 'AFFiNE'),
|
||||
borderRadius: '50%',
|
||||
textAlign: 'center',
|
||||
lineHeight: size + 'px',
|
||||
}}
|
||||
>
|
||||
{(props.name || 'AFFiNE').substring(0, 1)}
|
||||
</div>
|
||||
{props.avatar ? (
|
||||
<div
|
||||
style={{
|
||||
width: sizeStr,
|
||||
height: sizeStr,
|
||||
border: '1px solid #fff',
|
||||
color: '#fff',
|
||||
borderRadius: '50%',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<img src={props.avatar} alt="" />
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
width: sizeStr,
|
||||
height: sizeStr,
|
||||
border: '1px solid #fff',
|
||||
color: '#fff',
|
||||
fontSize: Math.ceil(0.5 * size) + 'px',
|
||||
background: stringToColour(props.name || 'AFFiNE'),
|
||||
borderRadius: '50%',
|
||||
textAlign: 'center',
|
||||
lineHeight: size + 'px',
|
||||
}}
|
||||
>
|
||||
{(props.name || 'AFFiNE').substring(0, 1)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,27 +10,24 @@ import {
|
||||
UsersIcon,
|
||||
AddIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useConfirm } from '@/providers/ConfirmProvider';
|
||||
// import { useConfirm } from '@/providers/ConfirmProvider';
|
||||
import { toast } from '@/ui/toast';
|
||||
import { WorkspaceAvatar } from '@/components/workspace-avatar';
|
||||
import { useTemporaryHelper } from '@/providers/temporary-helper-provider';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useUserHelper } from '@/hooks/use-user-helper';
|
||||
|
||||
interface LoginModalProps {
|
||||
interface WorkspaceModalProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
|
||||
export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => {
|
||||
const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false);
|
||||
const { confirm } = useConfirm();
|
||||
const {
|
||||
user,
|
||||
login,
|
||||
workspaceMetaList,
|
||||
setActiveWorkspace,
|
||||
updateWorkspaceMeta,
|
||||
} = useTemporaryHelper();
|
||||
|
||||
// const { confirm } = useConfirm();
|
||||
const { workspaceList, currentWorkspace } = useAppState();
|
||||
const { login, user } = useUserHelper();
|
||||
const router = useRouter();
|
||||
return (
|
||||
<div>
|
||||
<Modal open={open} onClose={onClose}>
|
||||
@@ -51,13 +48,14 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
|
||||
</Header>
|
||||
<Content>
|
||||
<WorkspaceList>
|
||||
{workspaceMetaList.map((item, index) => {
|
||||
{workspaceList.map((item, index) => {
|
||||
return (
|
||||
<WorkspaceItem
|
||||
onClick={() => {
|
||||
setActiveWorkspace(item);
|
||||
router.replace(`/workspace/${item.id}`);
|
||||
onClose();
|
||||
}}
|
||||
active={item.id === currentWorkspace.room}
|
||||
key={index}
|
||||
>
|
||||
<span style={{ width: '100px' }}>
|
||||
@@ -69,7 +67,11 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
|
||||
marginRight: '10px',
|
||||
}}
|
||||
>
|
||||
<WorkspaceAvatar size={50} name={item.name} />
|
||||
<WorkspaceAvatar
|
||||
size={50}
|
||||
name={item.name}
|
||||
avatar={item.avatar ?? ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<span
|
||||
@@ -93,10 +95,10 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
|
||||
top: '20px',
|
||||
}}
|
||||
>
|
||||
{(item.type === 'local' || !item.type) && (
|
||||
{(item.provider === 'local' || !item.provider) && (
|
||||
<CloudUnsyncedIcon fontSize={24} />
|
||||
)}
|
||||
{item.type === 'cloud' && (
|
||||
{item.provider === 'affine' && (
|
||||
<CloudInsyncIcon fontSize={24} />
|
||||
)}
|
||||
{item.isPublish && <UsersIcon fontSize={24} />}
|
||||
@@ -154,26 +156,26 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
|
||||
</Footer>
|
||||
<CreateWorkspaceModal
|
||||
open={createWorkspaceOpen}
|
||||
onClose={({ workspaceId }) => {
|
||||
onClose={() => {
|
||||
setCreateWorkspaceOpen(false);
|
||||
onClose();
|
||||
confirm({
|
||||
title: 'Enable AFFiNE Cloud?',
|
||||
content: `If enabled, the data in this workspace will be backed up and synchronized via AFFiNE Cloud.`,
|
||||
confirmText: user ? 'Enable' : 'Sign in and Enable',
|
||||
cancelText: 'Skip',
|
||||
}).then(confirm => {
|
||||
if (confirm) {
|
||||
if (user) {
|
||||
workspaceId &&
|
||||
updateWorkspaceMeta(workspaceId, { isPublish: true });
|
||||
} else {
|
||||
login();
|
||||
workspaceId &&
|
||||
updateWorkspaceMeta(workspaceId, { isPublish: true });
|
||||
}
|
||||
}
|
||||
});
|
||||
// confirm({
|
||||
// title: 'Enable AFFiNE Cloud?',
|
||||
// content: `If enabled, the data in this workspace will be backed up and synchronized via AFFiNE Cloud.`,
|
||||
// confirmText: user ? 'Enable' : 'Sign in and Enable',
|
||||
// cancelText: 'Skip',
|
||||
// }).then(confirm => {
|
||||
// if (confirm) {
|
||||
// if (user) {
|
||||
// // workspaceId &&
|
||||
// // updateWorkspaceMeta(workspaceId, { isPublish: true });
|
||||
// } else {
|
||||
// // login();
|
||||
// // workspaceId &&
|
||||
// // updateWorkspaceMeta(workspaceId, { isPublish: true });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
}}
|
||||
></CreateWorkspaceModal>
|
||||
</ModalWrapper>
|
||||
@@ -218,11 +220,17 @@ const WorkspaceList = styled('div')({
|
||||
gridTemplateColumns: 'repeat(2, 1fr)',
|
||||
});
|
||||
|
||||
const WorkspaceItem = styled('div')({
|
||||
cursor: 'pointer',
|
||||
padding: '8px',
|
||||
border: '1px solid #eee',
|
||||
':hover': {
|
||||
background: '#eee',
|
||||
},
|
||||
export const WorkspaceItem = styled.div<{
|
||||
active: boolean;
|
||||
}>(({ theme, active }) => {
|
||||
const backgroundColor = active ? theme.colors.hoverBackground : 'transparent';
|
||||
return {
|
||||
cursor: 'pointer',
|
||||
padding: '8px',
|
||||
border: '1px solid #eee',
|
||||
backgroundColor: backgroundColor,
|
||||
':hover': {
|
||||
background: theme.colors.hoverBackground,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Workspace } from '@/hooks/mock-data/mock';
|
||||
import { styled } from '@/styles';
|
||||
import { WorkspaceInfo } from '@affine/datacenter';
|
||||
|
||||
export const ExportPageTitleContainer = styled('div')(() => {
|
||||
return {
|
||||
@@ -9,7 +9,7 @@ export const ExportPageTitleContainer = styled('div')(() => {
|
||||
flex: 1,
|
||||
};
|
||||
});
|
||||
export const ExportPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
export const ExportPage = ({ workspace }: { workspace: WorkspaceInfo }) => {
|
||||
return (
|
||||
<ExportPageTitleContainer>
|
||||
Export Workspace{' '}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
StyledMemberRoleContainer,
|
||||
StyledMemberTitleContainer,
|
||||
StyledMoreVerticalButton,
|
||||
StyledPublishExplanation,
|
||||
} from './style';
|
||||
import { MoreVerticalIcon, EmailIcon, TrashIcon } from '@blocksuite/icons';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -17,20 +18,24 @@ import { Button, IconButton } from '@/ui/button';
|
||||
import { InviteMembers } from '../invite-members/index';
|
||||
import { Menu, MenuItem } from '@/ui/menu';
|
||||
import { Empty } from '@/ui/empty';
|
||||
import {
|
||||
deleteMember,
|
||||
getMembers,
|
||||
User,
|
||||
Workspace,
|
||||
} from '@/hooks/mock-data/mock';
|
||||
// import {
|
||||
// deleteMember,
|
||||
// getMembers,
|
||||
// User,
|
||||
// Workspace,
|
||||
// } from '@/hooks/mock-data/mock';
|
||||
import { WorkspaceInfo } from '@affine/datacenter';
|
||||
import { useTemporaryHelper } from '@/providers/temporary-helper-provider';
|
||||
import { StyledMemberWarp } from './general/style';
|
||||
import { useConfirm } from '@/providers/ConfirmProvider';
|
||||
|
||||
// import { useAppState } from '@/providers/app-state-provider';
|
||||
export const MembersPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
export const MembersPage = ({ workspace }: { workspace: WorkspaceInfo }) => {
|
||||
const [isInviteModalShow, setIsInviteModalShow] = useState(false);
|
||||
const [members, setMembers] = useState<User[]>([]);
|
||||
const [members, setMembers] = useState<[{ name: string; email: string }]>([
|
||||
{ name: 'affine', email: 'tttt' },
|
||||
]);
|
||||
console.log('setMembers: ', setMembers);
|
||||
const { user, login, updateWorkspaceMeta } = useTemporaryHelper();
|
||||
const { confirm } = useConfirm();
|
||||
// const refreshMembers = useCallback(() => {
|
||||
@@ -48,8 +53,9 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
// });
|
||||
// }, [workspace.id]);
|
||||
const setMembersList = () => {
|
||||
const members = getMembers(workspace.id);
|
||||
members && setMembers(members);
|
||||
// setMembers([]);
|
||||
// const members = getMembers(workspace.id);
|
||||
// members && setMembers(members);
|
||||
};
|
||||
useEffect(() => {
|
||||
setMembersList();
|
||||
@@ -58,7 +64,7 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
{workspace.type === 'cloud' ? (
|
||||
{workspace.provider === 'cloud' ? (
|
||||
<>
|
||||
<StyledMemberTitleContainer>
|
||||
<StyledMemberNameContainer>
|
||||
@@ -67,13 +73,6 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
<StyledMemberRoleContainer>Access level</StyledMemberRoleContainer>
|
||||
</StyledMemberTitleContainer>
|
||||
<StyledMemberListContainer>
|
||||
{members.length === 0 && (
|
||||
<Empty
|
||||
width={648}
|
||||
sx={{ marginTop: '60px' }}
|
||||
height={300}
|
||||
></Empty>
|
||||
)}
|
||||
{members.length ? (
|
||||
members.map((member, index) => {
|
||||
return (
|
||||
@@ -103,7 +102,7 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
<>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
deleteMember(workspace.id, 0);
|
||||
// deleteMember(workspace.id, 0);
|
||||
setMembersList();
|
||||
// confirm({
|
||||
// title: 'Delete Member?',
|
||||
@@ -142,7 +141,11 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<></>
|
||||
<Empty
|
||||
width={648}
|
||||
sx={{ marginTop: '60px' }}
|
||||
height={300}
|
||||
></Empty>
|
||||
)}
|
||||
</StyledMemberListContainer>
|
||||
<StyledMemberButtonContainer>
|
||||
@@ -171,10 +174,8 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
</>
|
||||
) : (
|
||||
<StyledMemberWarp>
|
||||
<div style={{ flex: 1 }}>
|
||||
Collaborating with other members requires AFFiNE Cloud service.
|
||||
</div>
|
||||
<div style={{ height: '40px' }}>
|
||||
<>Collaborating with other members requires AFFiNE Cloud service.</>
|
||||
<StyledPublishExplanation>
|
||||
<Button
|
||||
type="primary"
|
||||
shape="circle"
|
||||
@@ -198,7 +199,7 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
>
|
||||
Enable AFFiNE Cloud
|
||||
</Button>
|
||||
</div>
|
||||
</StyledPublishExplanation>
|
||||
</StyledMemberWarp>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -9,20 +9,20 @@ import {
|
||||
import { Button } from '@/ui/button';
|
||||
import Input from '@/ui/input';
|
||||
import { toast } from '@/ui/toast';
|
||||
import { Workspace } from '@/hooks/mock-data/mock';
|
||||
import { useTemporaryHelper } from '@/providers/temporary-helper-provider';
|
||||
import { useConfirm } from '@/providers/ConfirmProvider';
|
||||
// import { useAppState } from '@/providers/app-state-provider3';
|
||||
import { useWorkspaceHelper } from '@/hooks/use-workspace-helper';
|
||||
import { WorkspaceInfo } from '@affine/datacenter';
|
||||
|
||||
export const PublishPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
console.log('workspace: ', workspace);
|
||||
export const PublishPage = ({ workspace }: { workspace: WorkspaceInfo }) => {
|
||||
const shareUrl =
|
||||
window.location.host + '/workspace/' + workspace.id + '?share=true';
|
||||
const { publishWorkspace } = useWorkspaceHelper();
|
||||
|
||||
const { login, updateWorkspaceMeta, user } = useTemporaryHelper();
|
||||
const { confirm } = useConfirm();
|
||||
|
||||
const togglePublic = (flag: boolean) => {
|
||||
updateWorkspaceMeta(workspace.id, { isPublish: flag });
|
||||
workspace.id && publishWorkspace(workspace?.id, flag);
|
||||
};
|
||||
|
||||
const copyUrl = () => {
|
||||
@@ -34,22 +34,23 @@ export const PublishPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
confirm({
|
||||
title: 'Enable AFFiNE Cloud?',
|
||||
content: `If enabled, the data in this workspace will be backed up and synchronized via AFFiNE Cloud.`,
|
||||
confirmText: user ? 'Enable' : 'Sign in and Enable',
|
||||
confirmText:
|
||||
workspace.provider === 'local' ? 'Enable' : 'Sign in and Enable',
|
||||
cancelText: 'Skip',
|
||||
}).then(confirm => {
|
||||
if (confirm) {
|
||||
if (user) {
|
||||
updateWorkspaceMeta(workspace.id, { type: 'cloud' });
|
||||
} else {
|
||||
login();
|
||||
updateWorkspaceMeta(workspace.id, { type: 'cloud' });
|
||||
}
|
||||
// if (user) {
|
||||
// updateWorkspaceMeta(workspace.id, { type: 'cloud' });
|
||||
// } else {
|
||||
// login();
|
||||
// updateWorkspaceMeta(workspace.id, { type: 'cloud' });
|
||||
// }
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{workspace.type === 'cloud' ? (
|
||||
{workspace.provider === 'cloud' ? (
|
||||
<div>
|
||||
<StyledPublishContent>
|
||||
{workspace?.isPublish ? (
|
||||
|
||||
@@ -6,28 +6,48 @@ import {
|
||||
import { DownloadIcon } from '@blocksuite/icons';
|
||||
import { Button } from '@/ui/button';
|
||||
import { Menu, MenuItem } from '@/ui/menu';
|
||||
import { deleteMember, Workspace } from '@/hooks/mock-data/mock';
|
||||
import { useTemporaryHelper } from '@/providers/temporary-helper-provider';
|
||||
|
||||
export const SyncPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
const { currentWorkspace, updateWorkspaceMeta } = useTemporaryHelper();
|
||||
|
||||
import { WorkspaceInfo } from '@affine/datacenter';
|
||||
import { useWorkspaceHelper } from '@/hooks/use-workspace-helper';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useConfirm } from '@/providers/ConfirmProvider';
|
||||
import { toast } from '@/ui/toast';
|
||||
import { useUserHelper } from '@/hooks/use-user-helper';
|
||||
import { useRouter } from 'next/router';
|
||||
export const SyncPage = ({ workspace }: { workspace: WorkspaceInfo }) => {
|
||||
// console.log('workspace: ', workspace);
|
||||
const { enableWorkspace } = useWorkspaceHelper();
|
||||
const { currentWorkspace } = useAppState();
|
||||
const { confirm } = useConfirm();
|
||||
const { user, login } = useUserHelper();
|
||||
const router = useRouter();
|
||||
return (
|
||||
<div>
|
||||
<StyledPublishContent>
|
||||
{currentWorkspace?.type === 'local' ? (
|
||||
{workspace?.provider === 'local' ? (
|
||||
<>
|
||||
<StyledPublishExplanation>
|
||||
{currentWorkspace.name} is Local Workspace. All data is stored on
|
||||
the current device. You can enable AFFiNE Cloud for this workspace
|
||||
to keep data in sync with the cloud.
|
||||
{workspace.name ?? 'Affine'} is Local Workspace. All data is
|
||||
stored on the current device. You can enable AFFiNE Cloud for this
|
||||
workspace to keep data in sync with the cloud.
|
||||
</StyledPublishExplanation>
|
||||
|
||||
<StyledPublishCopyContainer>
|
||||
<Button
|
||||
onClick={() => {
|
||||
updateWorkspaceMeta(currentWorkspace.id, {
|
||||
type: 'cloud',
|
||||
confirm({
|
||||
title: 'Enable AFFiNE Cloud?',
|
||||
content: `If enabled, the data in this workspace will be backed up and synchronized via AFFiNE Cloud.`,
|
||||
confirmText: user ? 'Enable' : 'Sign in and Enable',
|
||||
cancelText: 'Skip',
|
||||
}).then(async confirm => {
|
||||
if (confirm) {
|
||||
// if (user) {
|
||||
// await login();
|
||||
// }
|
||||
const id = await enableWorkspace(currentWorkspace);
|
||||
router.push(`/workspace/${id}`);
|
||||
toast('Enabled success');
|
||||
}
|
||||
});
|
||||
}}
|
||||
type="primary"
|
||||
@@ -40,8 +60,8 @@ export const SyncPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
) : (
|
||||
<>
|
||||
<StyledPublishExplanation>
|
||||
<code>{currentWorkspace && currentWorkspace.name}</code> is Cloud
|
||||
Workspace. All data will be synchronized and saved to the AFFiNE
|
||||
<code>{workspace.name ?? 'Affine'}</code> is Cloud Workspace. All
|
||||
data will be synchronized and saved to the AFFiNE
|
||||
</StyledPublishExplanation>
|
||||
<StyledPublishCopyContainer>
|
||||
<Menu
|
||||
@@ -49,7 +69,7 @@ export const SyncPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
<>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
deleteMember(workspace.id, 0);
|
||||
// deleteMember(workspace.id, 0);
|
||||
}}
|
||||
icon={<DownloadIcon />}
|
||||
>
|
||||
@@ -57,7 +77,7 @@ export const SyncPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
deleteMember(workspace.id, 0);
|
||||
// deleteMember(workspace.id, 0);
|
||||
}}
|
||||
icon={<DownloadIcon />}
|
||||
>
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
import Modal, { ModalCloseButton } from '@/ui/modal';
|
||||
import {
|
||||
StyledSettingContainer,
|
||||
StyledSettingContent,
|
||||
StyledSettingSidebar,
|
||||
StyledSettingSidebarHeader,
|
||||
StyledSettingTabContainer,
|
||||
StyledSettingTagIconContainer,
|
||||
WorkspaceSettingTagItem,
|
||||
} from './style';
|
||||
import {
|
||||
EditIcon,
|
||||
UsersIcon,
|
||||
PublishIcon,
|
||||
CloudInsyncIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { GeneralPage } from './general';
|
||||
import { MembersPage } from './MembersPage';
|
||||
import { PublishPage } from './PublishPage';
|
||||
import { ExportPage } from './ExportPage';
|
||||
import { SyncPage } from './SyncPage';
|
||||
import { useTemporaryHelper } from '@/providers/temporary-helper-provider';
|
||||
|
||||
enum ActiveTab {
|
||||
'general' = 'general',
|
||||
'members' = 'members',
|
||||
'publish' = 'publish',
|
||||
'sync' = 'sync',
|
||||
'export' = 'export',
|
||||
}
|
||||
|
||||
type SettingTabProps = {
|
||||
activeTab: ActiveTab;
|
||||
onTabChange?: (tab: ActiveTab) => void;
|
||||
};
|
||||
|
||||
type WorkspaceSettingProps = {
|
||||
isShow: boolean;
|
||||
onClose?: () => void;
|
||||
};
|
||||
|
||||
const WorkspaceSettingTab = ({ activeTab, onTabChange }: SettingTabProps) => {
|
||||
return (
|
||||
<StyledSettingTabContainer>
|
||||
<WorkspaceSettingTagItem
|
||||
isActive={activeTab === ActiveTab.general}
|
||||
onClick={() => {
|
||||
onTabChange && onTabChange(ActiveTab.general);
|
||||
}}
|
||||
>
|
||||
<StyledSettingTagIconContainer>
|
||||
<EditIcon />
|
||||
</StyledSettingTagIconContainer>
|
||||
General
|
||||
</WorkspaceSettingTagItem>
|
||||
|
||||
<WorkspaceSettingTagItem
|
||||
isActive={activeTab === ActiveTab.sync}
|
||||
onClick={() => {
|
||||
onTabChange && onTabChange(ActiveTab.sync);
|
||||
}}
|
||||
>
|
||||
<StyledSettingTagIconContainer>
|
||||
<CloudInsyncIcon />
|
||||
</StyledSettingTagIconContainer>
|
||||
Sync
|
||||
</WorkspaceSettingTagItem>
|
||||
|
||||
<WorkspaceSettingTagItem
|
||||
isActive={activeTab === ActiveTab.members}
|
||||
onClick={() => {
|
||||
onTabChange && onTabChange(ActiveTab.members);
|
||||
}}
|
||||
>
|
||||
<StyledSettingTagIconContainer>
|
||||
<UsersIcon />
|
||||
</StyledSettingTagIconContainer>
|
||||
Collaboration
|
||||
</WorkspaceSettingTagItem>
|
||||
<WorkspaceSettingTagItem
|
||||
isActive={activeTab === ActiveTab.publish}
|
||||
onClick={() => {
|
||||
onTabChange && onTabChange(ActiveTab.publish);
|
||||
}}
|
||||
>
|
||||
<StyledSettingTagIconContainer>
|
||||
<PublishIcon />
|
||||
</StyledSettingTagIconContainer>
|
||||
Publish
|
||||
</WorkspaceSettingTagItem>
|
||||
|
||||
<WorkspaceSettingTagItem
|
||||
isActive={activeTab === ActiveTab.export}
|
||||
onClick={() => {
|
||||
onTabChange && onTabChange(ActiveTab.export);
|
||||
}}
|
||||
>
|
||||
<StyledSettingTagIconContainer>
|
||||
<PublishIcon />
|
||||
</StyledSettingTagIconContainer>
|
||||
Export
|
||||
</WorkspaceSettingTagItem>
|
||||
</StyledSettingTabContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const WorkspaceSetting = ({
|
||||
isShow,
|
||||
onClose,
|
||||
}: WorkspaceSettingProps) => {
|
||||
// const { workspaces } = useAppState();
|
||||
const [activeTab, setActiveTab] = useState<ActiveTab>(ActiveTab.general);
|
||||
const handleTabChange = (tab: ActiveTab) => {
|
||||
setActiveTab(tab);
|
||||
};
|
||||
|
||||
const { currentWorkspace } = useTemporaryHelper();
|
||||
const handleClickClose = () => {
|
||||
onClose && onClose();
|
||||
};
|
||||
const isOwner = true;
|
||||
useEffect(() => {
|
||||
// reset tab when modal is closed
|
||||
if (!isShow) {
|
||||
setActiveTab(ActiveTab.general);
|
||||
}
|
||||
}, [isShow]);
|
||||
return (
|
||||
<Modal open={isShow}>
|
||||
<StyledSettingContainer>
|
||||
<ModalCloseButton onClick={handleClickClose} />
|
||||
{isOwner ? (
|
||||
<StyledSettingSidebar>
|
||||
<StyledSettingSidebarHeader>
|
||||
Workspace Settings
|
||||
</StyledSettingSidebarHeader>
|
||||
<WorkspaceSettingTab
|
||||
activeTab={activeTab}
|
||||
onTabChange={handleTabChange}
|
||||
/>
|
||||
</StyledSettingSidebar>
|
||||
) : null}
|
||||
<StyledSettingContent>
|
||||
{activeTab === ActiveTab.general && currentWorkspace && (
|
||||
<GeneralPage workspace={currentWorkspace} />
|
||||
)}
|
||||
{activeTab === ActiveTab.sync && currentWorkspace && (
|
||||
<SyncPage workspace={currentWorkspace} />
|
||||
)}
|
||||
{activeTab === ActiveTab.members && currentWorkspace && (
|
||||
<MembersPage workspace={currentWorkspace} />
|
||||
)}
|
||||
{activeTab === ActiveTab.publish && currentWorkspace && (
|
||||
<PublishPage workspace={currentWorkspace} />
|
||||
)}
|
||||
{activeTab === ActiveTab.export && currentWorkspace && (
|
||||
<ExportPage workspace={currentWorkspace} />
|
||||
)}
|
||||
</StyledSettingContent>
|
||||
</StyledSettingContainer>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -9,26 +9,21 @@ import { StyledSettingH2 } from '../style';
|
||||
import { useState } from 'react';
|
||||
import { Button, TextButton } from '@/ui/button';
|
||||
import Input from '@/ui/input';
|
||||
// import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { WorkspaceDelete } from './delete';
|
||||
// import { debounce } from '@/utils';
|
||||
import { WorkspaceLeave } from './leave';
|
||||
import { Upload } from '@/components/file-upload';
|
||||
import { Workspace } from '@/hooks/mock-data/mock';
|
||||
import { WorkspaceAvatar } from '@/components/workspace-avatar';
|
||||
import { useTemporaryHelper } from '@/providers/temporary-helper-provider';
|
||||
export const GeneralPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
// const { refreshWorkspacesMeta } = useAppState();
|
||||
const { updateWorkspaceMeta } = useTemporaryHelper();
|
||||
import { WorkspaceInfo } from '@affine/datacenter';
|
||||
import { useWorkspaceHelper } from '@/hooks/use-workspace-helper';
|
||||
export const GeneralPage = ({ workspace }: { workspace: WorkspaceInfo }) => {
|
||||
const [showDelete, setShowDelete] = useState<boolean>(false);
|
||||
const [showLeave, setShowLeave] = useState<boolean>(false);
|
||||
const [uploading, setUploading] = useState<boolean>(false);
|
||||
const [workspaceName, setWorkspaceName] = useState<string>('');
|
||||
// const debouncedRefreshWorkspacesMeta = debounce(() => {
|
||||
// refreshWorkspacesMeta();
|
||||
// }, 100);
|
||||
const [workspaceName, setWorkspaceName] = useState<string>(workspace.name);
|
||||
const { currentWorkspace } = useAppState();
|
||||
const { updateWorkspace } = useWorkspaceHelper();
|
||||
const isOwner = true;
|
||||
|
||||
const handleChangeWorkSpaceName = (newName: string) => {
|
||||
setWorkspaceName(newName);
|
||||
};
|
||||
@@ -46,24 +41,15 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
setShowLeave(false);
|
||||
};
|
||||
const handleUpdateWorkspaceName = () => {
|
||||
workspace && updateWorkspaceMeta(workspace.id, { name: workspaceName });
|
||||
console.log('currentWorkspace: ', currentWorkspace);
|
||||
updateWorkspace({ name: workspaceName }, currentWorkspace);
|
||||
};
|
||||
|
||||
const fileChange = async (file: File) => {
|
||||
console.log('file: ', file);
|
||||
setUploading(true);
|
||||
// const blob = new Blob([file], { type: file.type });
|
||||
// const blobId = await getDataCenter()
|
||||
// .then(dc => dc.apis.uploadBlob({ blob }))
|
||||
// .finally(() => {
|
||||
// setUploading(false);
|
||||
// });
|
||||
// if (blobId) {
|
||||
// currentWorkspace?.meta.setAvatar(blobId);
|
||||
// // workspaces[workspace.id]?.meta.setAvatar(blobId);
|
||||
// setUploading(false);
|
||||
// debouncedRefreshWorkspacesMeta();
|
||||
// }
|
||||
// console.log('file: ', file);
|
||||
// setUploading(true);
|
||||
const blob = new Blob([file], { type: file.type });
|
||||
updateWorkspace({ avatarBlob: blob }, currentWorkspace);
|
||||
};
|
||||
|
||||
return workspace ? (
|
||||
@@ -73,11 +59,14 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
<div
|
||||
style={{
|
||||
float: 'left',
|
||||
|
||||
marginRight: '5px',
|
||||
marginRight: '20px',
|
||||
}}
|
||||
>
|
||||
<WorkspaceAvatar size={60} name={workspace.name} />
|
||||
<WorkspaceAvatar
|
||||
size={60}
|
||||
name={workspace.name}
|
||||
avatar={workspace.avatar ?? ''}
|
||||
/>
|
||||
</div>
|
||||
<Upload
|
||||
accept="image/gif,image/jpeg,image/jpg,image/png,image/svg"
|
||||
@@ -101,30 +90,14 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => {
|
||||
onClick={() => {
|
||||
handleUpdateWorkspaceName();
|
||||
}}
|
||||
style={{ marginLeft: '10px' }}
|
||||
style={{ marginLeft: '0px' }}
|
||||
>
|
||||
✔️
|
||||
</TextButton>
|
||||
</StyledSettingInputContainer>
|
||||
{/* {userInfo ? (
|
||||
<div>
|
||||
<StyledSettingH2 marginTop={20}>Workspace Owner</StyledSettingH2>
|
||||
<StyledSettingInputContainer>
|
||||
<Input
|
||||
width={327}
|
||||
disabled
|
||||
value={userInfo?.name}
|
||||
placeholder="Workspace Owner"
|
||||
></Input>
|
||||
</StyledSettingInputContainer>
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
)} */}
|
||||
|
||||
<StyledSettingH2 marginTop={20}>Workspace Type</StyledSettingH2>
|
||||
<StyledSettingInputContainer>
|
||||
<code>{workspace.type} </code>
|
||||
<code>{workspace.provider} </code>
|
||||
</StyledSettingInputContainer>
|
||||
<StyledDeleteButtonContainer>
|
||||
{isOwner ? (
|
||||
|
||||
@@ -15,13 +15,14 @@ import { useRouter } from 'next/router';
|
||||
import {
|
||||
deleteWorkspace,
|
||||
getWorkspaces,
|
||||
Workspace,
|
||||
// Workspace,
|
||||
} from '@/hooks/mock-data/mock';
|
||||
import { WorkspaceInfo } from '@affine/datacenter';
|
||||
|
||||
interface WorkspaceDeleteProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
workspace: Workspace;
|
||||
workspace: WorkspaceInfo;
|
||||
}
|
||||
|
||||
export const WorkspaceDelete = ({
|
||||
@@ -55,7 +56,7 @@ export const WorkspaceDelete = ({
|
||||
<StyledModalWrapper>
|
||||
<ModalCloseButton onClick={onClose} />
|
||||
<StyledModalHeader>Delete Workspace</StyledModalHeader>
|
||||
{workspace.type === 'local' ? (
|
||||
{workspace.provider === 'local' ? (
|
||||
<StyledTextContent>
|
||||
Deleting (
|
||||
<StyledWorkspaceName>{workspace.name}</StyledWorkspaceName>) cannot
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './Delete';
|
||||
export { WorkspaceDelete } from './Delete';
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './General';
|
||||
export { GeneralPage } from './General';
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import { ModalCloseButton } from '@/ui/modal';
|
||||
import { Button } from '@/ui/button';
|
||||
// import { getDataCenter } from '@affine/datacenter';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
// import { useAppState } from '@/providers/app-state-provider';
|
||||
|
||||
interface WorkspaceDeleteProps {
|
||||
open: boolean;
|
||||
@@ -22,8 +22,9 @@ export const WorkspaceLeave = ({
|
||||
onClose,
|
||||
workspaceId,
|
||||
}: WorkspaceDeleteProps) => {
|
||||
console.log('workspaceId: ', workspaceId);
|
||||
// const router = useRouter();
|
||||
const { refreshWorkspacesMeta } = useAppState();
|
||||
// const { refreshWorkspacesMeta } = useAppState();
|
||||
const handleLeave = async () => {
|
||||
// const dc = await getDataCenter();
|
||||
// await dc.apis.leaveWorkspace({ id: workspaceId });
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './Leave';
|
||||
export { WorkspaceLeave } from './Leave';
|
||||
|
||||
@@ -30,8 +30,7 @@ export const StyledSettingAvatar = styled(MuiAvatar)(() => {
|
||||
export const StyledMemberWarp = styled('div')(() => {
|
||||
return {
|
||||
display: 'flex',
|
||||
height: '500px',
|
||||
flexDirection: 'column',
|
||||
padding: '60px 0',
|
||||
padding: '40px 0',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
export * from './WorkspaceSetting';
|
||||
export * from './general';
|
||||
export * from './ExportPage';
|
||||
export * from './MembersPage';
|
||||
export * from './SyncPage';
|
||||
export * from './PublishPage';
|
||||
|
||||
@@ -4,22 +4,17 @@ import MuiAvatar from '@mui/material/Avatar';
|
||||
|
||||
export const StyledSettingContainer = styled('div')(({ theme }) => {
|
||||
return {
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
padding: '0px',
|
||||
width: '961px',
|
||||
background: theme.colors.popoverBackground,
|
||||
borderRadius: '12px',
|
||||
overflow: 'hidden',
|
||||
padding: '50px',
|
||||
flexDirection: 'column',
|
||||
height: '100vh',
|
||||
overflow: 'auto',
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledSettingSidebar = styled('div')(({ theme }) => {
|
||||
{
|
||||
return {
|
||||
width: '212px',
|
||||
height: '620px',
|
||||
background: theme.mode === 'dark' ? '#272727' : '#FBFBFC',
|
||||
flexShrink: 0,
|
||||
flexGrow: 0,
|
||||
};
|
||||
@@ -29,7 +24,6 @@ export const StyledSettingSidebar = styled('div')(({ theme }) => {
|
||||
export const StyledSettingContent = styled('div')(() => {
|
||||
return {
|
||||
paddingLeft: '48px',
|
||||
height: '620px',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -37,7 +31,6 @@ export const StyledSetting = styled('div')(({ theme }) => {
|
||||
{
|
||||
return {
|
||||
width: '236px',
|
||||
height: '620px',
|
||||
background: theme.mode === 'dark' ? '#272727' : '#FBFBFC',
|
||||
};
|
||||
}
|
||||
@@ -49,7 +42,7 @@ export const StyledSettingSidebarHeader = styled('div')(() => {
|
||||
fontWeight: '500',
|
||||
fontSize: '18px',
|
||||
lineHeight: '26px',
|
||||
textAlign: 'center',
|
||||
textAlign: 'left',
|
||||
marginTop: '37px',
|
||||
};
|
||||
}
|
||||
@@ -59,7 +52,6 @@ export const StyledSettingTabContainer = styled('ul')(() => {
|
||||
{
|
||||
return {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
marginTop: '25px',
|
||||
};
|
||||
}
|
||||
@@ -144,7 +136,6 @@ export const StyledMemberRoleContainer = styled('div')(() => {
|
||||
export const StyledMemberListContainer = styled('ul')(() => {
|
||||
return {
|
||||
marginTop: '15px',
|
||||
height: '432px',
|
||||
overflowY: 'scroll',
|
||||
};
|
||||
});
|
||||
@@ -228,7 +219,6 @@ export const StyledCopyButtonContainer = styled('div')(() => {
|
||||
|
||||
export const StyledPublishContent = styled('div')(() => {
|
||||
return {
|
||||
height: '494px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
};
|
||||
|
||||
+180
-177
@@ -1,180 +1,183 @@
|
||||
import { InformationIcon, LogOutIcon } from '@blocksuite/icons';
|
||||
import { styled } from '@/styles';
|
||||
import { Divider } from '@/ui/divider';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import { SelectorPopperContainer } from './styles';
|
||||
import {
|
||||
PrivateWorkspaceItem,
|
||||
WorkspaceItem,
|
||||
CreateWorkspaceItem,
|
||||
ListItem,
|
||||
LoginItem,
|
||||
} from './WorkspaceItem';
|
||||
import { WorkspaceSetting } from '@/components/workspace-setting';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { WorkspaceType } from '@affine/datacenter';
|
||||
import { useModal } from '@/providers/GlobalModalProvider';
|
||||
// import { InformationIcon, LogOutIcon } from '@blocksuite/icons';
|
||||
// import { styled } from '@/styles';
|
||||
// import { Divider } from '@/ui/divider';
|
||||
// import { useAppState } from '@/providers/app-state-provider';
|
||||
// import { SelectorPopperContainer } from './styles';
|
||||
// import {
|
||||
// PrivateWorkspaceItem,
|
||||
// WorkspaceItem,
|
||||
// CreateWorkspaceItem,
|
||||
// ListItem,
|
||||
// LoginItem,
|
||||
// } from './WorkspaceItem';
|
||||
// import { WorkspaceSetting } from '@/components/workspace-setting';
|
||||
// import { useCallback, useEffect, useState } from 'react';
|
||||
// import { WorkspaceInfo } from '@affine/datacenter';
|
||||
// import { useModal } from '@/providers/GlobalModalProvider';
|
||||
|
||||
export type WorkspaceDetails = Record<
|
||||
string,
|
||||
{ memberCount: number; owner: { id: string; name: string } }
|
||||
>;
|
||||
// export type WorkspaceDetails = Record<
|
||||
// string,
|
||||
// { memberCount: number; owner: { id: string; name: string } }
|
||||
// >;
|
||||
|
||||
type SelectorPopperContentProps = {
|
||||
isShow: boolean;
|
||||
// type SelectorPopperContentProps = {
|
||||
// isShow: boolean;
|
||||
// };
|
||||
|
||||
// export const SelectorPopperContent = ({
|
||||
// isShow,
|
||||
// }: SelectorPopperContentProps) => {
|
||||
// const { user, workspacesMeta, refreshWorkspacesMeta } = useAppState();
|
||||
// const [settingWorkspaceId, setSettingWorkspaceId] = useState<string | null>(
|
||||
// null
|
||||
// );
|
||||
// const [workSpaceDetails, setWorkSpaceDetails] = useState<WorkspaceDetails>(
|
||||
// {}
|
||||
// );
|
||||
// const { triggerContactModal } = useModal();
|
||||
|
||||
// const handleClickSettingWorkspace = (workspaceId: string) => {
|
||||
// setSettingWorkspaceId(workspaceId);
|
||||
// };
|
||||
// const handleCloseWorkSpace = () => {
|
||||
// setSettingWorkspaceId(null);
|
||||
// };
|
||||
// const settingWorkspace = settingWorkspaceId
|
||||
// ? workspacesMeta.find(workspace => workspace.id === settingWorkspaceId)
|
||||
// : undefined;
|
||||
|
||||
// const refreshDetails = useCallback(async () => {
|
||||
// const workspaceDetailList = await Promise.all(
|
||||
// workspacesMeta.map(async ({ id, type }) => {
|
||||
// if (user) {
|
||||
// if (type === WorkspaceType.Private) {
|
||||
// return { id, member_count: 1, owner: user };
|
||||
// } else {
|
||||
// // const dc = await getDataCenter();
|
||||
// // const data = await dc.apis.getWorkspaceDetail({ id });
|
||||
// // return { id, ...data } || { id, member_count: 0, owner: user };
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// );
|
||||
// const workSpaceDetails: WorkspaceDetails = {};
|
||||
// workspaceDetailList.forEach(details => {
|
||||
// if (details) {
|
||||
// const { id, member_count, owner } = details;
|
||||
// if (!owner) return;
|
||||
// workSpaceDetails[id] = {
|
||||
// memberCount: member_count || 1,
|
||||
// owner: {
|
||||
// id: owner.id,
|
||||
// name: owner.name,
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
// });
|
||||
// setWorkSpaceDetails(workSpaceDetails);
|
||||
// }, [user, workspacesMeta]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (isShow) {
|
||||
// setSettingWorkspaceId(null);
|
||||
// refreshWorkspacesMeta();
|
||||
// refreshDetails();
|
||||
// }
|
||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// }, [isShow]);
|
||||
|
||||
// return !user ? (
|
||||
// <SelectorPopperContainer placement="bottom-start">
|
||||
// <LoginItem />
|
||||
// <StyledDivider />
|
||||
// <ListItem
|
||||
// icon={<InformationIcon />}
|
||||
// name="About AFFiNE"
|
||||
// onClick={() => triggerContactModal()}
|
||||
// />
|
||||
// </SelectorPopperContainer>
|
||||
// ) : (
|
||||
// <SelectorPopperContainer placement="bottom-start">
|
||||
// <PrivateWorkspaceItem
|
||||
// privateWorkspaceId={
|
||||
// workspacesMeta.find(
|
||||
// workspace => workspace.type === WorkspaceType.Private
|
||||
// )?.id
|
||||
// }
|
||||
// />
|
||||
// <StyledDivider />
|
||||
// <WorkspaceGroupTitle>Workspace</WorkspaceGroupTitle>
|
||||
// <WorkspaceWrapper>
|
||||
// {workspacesMeta.map(workspace => {
|
||||
// return workspace.type !== WorkspaceType.Private ? (
|
||||
// <WorkspaceItem
|
||||
// type={workspace.type}
|
||||
// key={workspace.id}
|
||||
// id={workspace.id}
|
||||
// icon={`loading...`}
|
||||
// onClickSetting={handleClickSettingWorkspace}
|
||||
// name={`loading...`}
|
||||
// memberCount={workSpaceDetails[workspace.id]?.memberCount || 1}
|
||||
// />
|
||||
// ) : null;
|
||||
// })}
|
||||
// </WorkspaceWrapper>
|
||||
// <CreateWorkspaceItem />
|
||||
// {settingWorkspace ? (
|
||||
// <WorkspaceSetting
|
||||
// isShow={false}
|
||||
// onClose={handleCloseWorkSpace}
|
||||
// // workspace={settingWorkspace}
|
||||
// // owner={
|
||||
// // (settingWorkspaceId &&
|
||||
// // workSpaceDetails[settingWorkspaceId]?.owner) || {
|
||||
// // id: user.id,
|
||||
// // name: user.name,
|
||||
// // }
|
||||
// // }
|
||||
// />
|
||||
// ) : null}
|
||||
// <StyledDivider />
|
||||
// <ListItem
|
||||
// icon={<InformationIcon />}
|
||||
// name="About AFFiNE"
|
||||
// onClick={() => triggerContactModal()}
|
||||
// />
|
||||
// <ListItem
|
||||
// icon={<LogOutIcon />}
|
||||
// name="Sign out"
|
||||
// onClick={() => {
|
||||
// console.log('Sign out');
|
||||
// // FIXME: remove token from local storage and reload the page
|
||||
// localStorage.removeItem('affine_token');
|
||||
// window.location.reload();
|
||||
// }}
|
||||
// />
|
||||
// </SelectorPopperContainer>
|
||||
// );
|
||||
// };
|
||||
|
||||
// const StyledDivider = styled(Divider)({
|
||||
// margin: '8px 12px',
|
||||
// width: 'calc(100% - 24px)',
|
||||
// });
|
||||
|
||||
// const WorkspaceGroupTitle = styled('div')(({ theme }) => {
|
||||
// return {
|
||||
// color: theme.colors.iconColor,
|
||||
// fontSize: theme.font.sm,
|
||||
// lineHeight: '30px',
|
||||
// height: '30px',
|
||||
// padding: '0 12px',
|
||||
// };
|
||||
// });
|
||||
|
||||
// const WorkspaceWrapper = styled('div')(() => {
|
||||
// return {
|
||||
// maxHeight: '200px',
|
||||
// overflow: 'auto',
|
||||
// };
|
||||
// });
|
||||
export const test = () => {
|
||||
return <></>;
|
||||
};
|
||||
|
||||
export const SelectorPopperContent = ({
|
||||
isShow,
|
||||
}: SelectorPopperContentProps) => {
|
||||
const { user, workspacesMeta, refreshWorkspacesMeta } = useAppState();
|
||||
const [settingWorkspaceId, setSettingWorkspaceId] = useState<string | null>(
|
||||
null
|
||||
);
|
||||
const [workSpaceDetails, setWorkSpaceDetails] = useState<WorkspaceDetails>(
|
||||
{}
|
||||
);
|
||||
const { triggerContactModal } = useModal();
|
||||
|
||||
const handleClickSettingWorkspace = (workspaceId: string) => {
|
||||
setSettingWorkspaceId(workspaceId);
|
||||
};
|
||||
const handleCloseWorkSpace = () => {
|
||||
setSettingWorkspaceId(null);
|
||||
};
|
||||
const settingWorkspace = settingWorkspaceId
|
||||
? workspacesMeta.find(workspace => workspace.id === settingWorkspaceId)
|
||||
: undefined;
|
||||
|
||||
const refreshDetails = useCallback(async () => {
|
||||
const workspaceDetailList = await Promise.all(
|
||||
workspacesMeta.map(async ({ id, type }) => {
|
||||
if (user) {
|
||||
if (type === WorkspaceType.Private) {
|
||||
return { id, member_count: 1, owner: user };
|
||||
} else {
|
||||
// const dc = await getDataCenter();
|
||||
// const data = await dc.apis.getWorkspaceDetail({ id });
|
||||
// return { id, ...data } || { id, member_count: 0, owner: user };
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
const workSpaceDetails: WorkspaceDetails = {};
|
||||
workspaceDetailList.forEach(details => {
|
||||
if (details) {
|
||||
const { id, member_count, owner } = details;
|
||||
if (!owner) return;
|
||||
workSpaceDetails[id] = {
|
||||
memberCount: member_count || 1,
|
||||
owner: {
|
||||
id: owner.id,
|
||||
name: owner.name,
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
setWorkSpaceDetails(workSpaceDetails);
|
||||
}, [user, workspacesMeta]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isShow) {
|
||||
setSettingWorkspaceId(null);
|
||||
refreshWorkspacesMeta();
|
||||
refreshDetails();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isShow]);
|
||||
|
||||
return !user ? (
|
||||
<SelectorPopperContainer placement="bottom-start">
|
||||
<LoginItem />
|
||||
<StyledDivider />
|
||||
<ListItem
|
||||
icon={<InformationIcon />}
|
||||
name="About AFFiNE"
|
||||
onClick={() => triggerContactModal()}
|
||||
/>
|
||||
</SelectorPopperContainer>
|
||||
) : (
|
||||
<SelectorPopperContainer placement="bottom-start">
|
||||
<PrivateWorkspaceItem
|
||||
privateWorkspaceId={
|
||||
workspacesMeta.find(
|
||||
workspace => workspace.type === WorkspaceType.Private
|
||||
)?.id
|
||||
}
|
||||
/>
|
||||
<StyledDivider />
|
||||
<WorkspaceGroupTitle>Workspace</WorkspaceGroupTitle>
|
||||
<WorkspaceWrapper>
|
||||
{workspacesMeta.map(workspace => {
|
||||
return workspace.type !== WorkspaceType.Private ? (
|
||||
<WorkspaceItem
|
||||
type={workspace.type}
|
||||
key={workspace.id}
|
||||
id={workspace.id}
|
||||
icon={`loading...`}
|
||||
onClickSetting={handleClickSettingWorkspace}
|
||||
name={`loading...`}
|
||||
memberCount={workSpaceDetails[workspace.id]?.memberCount || 1}
|
||||
/>
|
||||
) : null;
|
||||
})}
|
||||
</WorkspaceWrapper>
|
||||
<CreateWorkspaceItem />
|
||||
{settingWorkspace ? (
|
||||
<WorkspaceSetting
|
||||
isShow={false}
|
||||
onClose={handleCloseWorkSpace}
|
||||
// workspace={settingWorkspace}
|
||||
// owner={
|
||||
// (settingWorkspaceId &&
|
||||
// workSpaceDetails[settingWorkspaceId]?.owner) || {
|
||||
// id: user.id,
|
||||
// name: user.name,
|
||||
// }
|
||||
// }
|
||||
/>
|
||||
) : null}
|
||||
<StyledDivider />
|
||||
<ListItem
|
||||
icon={<InformationIcon />}
|
||||
name="About AFFiNE"
|
||||
onClick={() => triggerContactModal()}
|
||||
/>
|
||||
<ListItem
|
||||
icon={<LogOutIcon />}
|
||||
name="Sign out"
|
||||
onClick={() => {
|
||||
console.log('Sign out');
|
||||
// FIXME: remove token from local storage and reload the page
|
||||
localStorage.removeItem('affine_token');
|
||||
window.location.reload();
|
||||
}}
|
||||
/>
|
||||
</SelectorPopperContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const StyledDivider = styled(Divider)({
|
||||
margin: '8px 12px',
|
||||
width: 'calc(100% - 24px)',
|
||||
});
|
||||
|
||||
const WorkspaceGroupTitle = styled('div')(({ theme }) => {
|
||||
return {
|
||||
color: theme.colors.iconColor,
|
||||
fontSize: theme.font.sm,
|
||||
lineHeight: '30px',
|
||||
height: '30px',
|
||||
padding: '0 12px',
|
||||
};
|
||||
});
|
||||
|
||||
const WorkspaceWrapper = styled('div')(() => {
|
||||
return {
|
||||
maxHeight: '200px',
|
||||
overflow: 'auto',
|
||||
};
|
||||
});
|
||||
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
import { getDataCenter } from '@affine/datacenter';
|
||||
// import { getDataCenter } from '@affine/datacenter';
|
||||
import Modal from '@/ui/modal';
|
||||
import Input from '@/ui/input';
|
||||
import {
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
} from './style';
|
||||
import { useState } from 'react';
|
||||
import { ModalCloseButton } from '@/ui/modal';
|
||||
import router from 'next/router';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
// import router from 'next/router';
|
||||
// import { useAppState } from '@/providers/app-state-provider';
|
||||
|
||||
interface WorkspaceCreateProps {
|
||||
open: boolean;
|
||||
@@ -30,7 +30,7 @@ const DefaultHeadImgColors = [
|
||||
export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => {
|
||||
const [workspaceName, setWorkspaceId] = useState<string>('');
|
||||
const [creating, setCreating] = useState<boolean>(false);
|
||||
const { refreshWorkspacesMeta } = useAppState();
|
||||
// const { refreshWorkspacesMeta } = useAppState();
|
||||
const handlerInputChange = (workspaceName: string) => {
|
||||
setWorkspaceId(workspaceName);
|
||||
};
|
||||
|
||||
+61
-58
@@ -1,60 +1,63 @@
|
||||
import { styled } from '@/styles';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import {
|
||||
WorkspaceItemAvatar,
|
||||
PrivateWorkspaceWrapper,
|
||||
WorkspaceItemContent,
|
||||
} from './styles';
|
||||
import { useRouter } from 'next/router';
|
||||
// import { styled } from '@/styles';
|
||||
// import { useAppState } from '@/providers/app-state-provider';
|
||||
// import {
|
||||
// WorkspaceItemAvatar,
|
||||
// PrivateWorkspaceWrapper,
|
||||
// WorkspaceItemContent,
|
||||
// } from './styles';
|
||||
// import { useRouter } from 'next/router';
|
||||
|
||||
type PrivateWorkspaceItemProps = {
|
||||
privateWorkspaceId?: string;
|
||||
// type PrivateWorkspaceItemProps = {
|
||||
// privateWorkspaceId?: string;
|
||||
// };
|
||||
|
||||
// export const PrivateWorkspaceItem = ({
|
||||
// privateWorkspaceId,
|
||||
// }: PrivateWorkspaceItemProps) => {
|
||||
// const { user } = useAppState();
|
||||
// const router = useRouter();
|
||||
// const handleClick = () => {
|
||||
// if (privateWorkspaceId) {
|
||||
// router.push(`/workspace/${privateWorkspaceId}`);
|
||||
// }
|
||||
// };
|
||||
// if (user) {
|
||||
// const Username = user.name;
|
||||
// return (
|
||||
// <PrivateWorkspaceWrapper onClick={handleClick}>
|
||||
// <WorkspaceItemAvatar alt={Username} src={user.avatar_url}>
|
||||
// {Username}
|
||||
// </WorkspaceItemAvatar>
|
||||
// <WorkspaceItemContent>
|
||||
// <Name title={Username}>{Username}</Name>
|
||||
// <Email title={user.email}>{user.email}</Email>
|
||||
// </WorkspaceItemContent>
|
||||
// </PrivateWorkspaceWrapper>
|
||||
// );
|
||||
// }
|
||||
// return null;
|
||||
// };
|
||||
|
||||
// const Name = styled('div')(({ theme }) => {
|
||||
// return {
|
||||
// color: theme.colors.quoteColor,
|
||||
// fontSize: theme.font.base,
|
||||
// fontWeight: 500,
|
||||
// overflow: 'hidden',
|
||||
// textOverflow: 'ellipsis',
|
||||
// whiteSpace: 'nowrap',
|
||||
// };
|
||||
// });
|
||||
|
||||
// const Email = styled('div')(({ theme }) => {
|
||||
// return {
|
||||
// color: theme.colors.iconColor,
|
||||
// fontSize: theme.font.sm,
|
||||
// overflow: 'hidden',
|
||||
// textOverflow: 'ellipsis',
|
||||
// whiteSpace: 'nowrap',
|
||||
// };
|
||||
// });
|
||||
export const test = () => {
|
||||
return <></>;
|
||||
};
|
||||
|
||||
export const PrivateWorkspaceItem = ({
|
||||
privateWorkspaceId,
|
||||
}: PrivateWorkspaceItemProps) => {
|
||||
const { user } = useAppState();
|
||||
const router = useRouter();
|
||||
const handleClick = () => {
|
||||
if (privateWorkspaceId) {
|
||||
router.push(`/workspace/${privateWorkspaceId}`);
|
||||
}
|
||||
};
|
||||
if (user) {
|
||||
const Username = user.name;
|
||||
return (
|
||||
<PrivateWorkspaceWrapper onClick={handleClick}>
|
||||
<WorkspaceItemAvatar alt={Username} src={user.avatar_url}>
|
||||
{Username}
|
||||
</WorkspaceItemAvatar>
|
||||
<WorkspaceItemContent>
|
||||
<Name title={Username}>{Username}</Name>
|
||||
<Email title={user.email}>{user.email}</Email>
|
||||
</WorkspaceItemContent>
|
||||
</PrivateWorkspaceWrapper>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const Name = styled('div')(({ theme }) => {
|
||||
return {
|
||||
color: theme.colors.quoteColor,
|
||||
fontSize: theme.font.base,
|
||||
fontWeight: 500,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
};
|
||||
});
|
||||
|
||||
const Email = styled('div')(({ theme }) => {
|
||||
return {
|
||||
color: theme.colors.iconColor,
|
||||
fontSize: theme.font.sm,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
};
|
||||
});
|
||||
|
||||
+94
-90
@@ -1,96 +1,100 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import { styled } from '@/styles';
|
||||
import {
|
||||
WorkspaceItemAvatar,
|
||||
WorkspaceItemWrapper,
|
||||
WorkspaceItemContent,
|
||||
} from '../styles';
|
||||
import { FooterSetting } from './FooterSetting';
|
||||
import { FooterUsers } from './FooterUsers';
|
||||
import { WorkspaceType } from '@affine/datacenter';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
// import { useRouter } from 'next/router';
|
||||
// import { styled } from '@/styles';
|
||||
// import {
|
||||
// WorkspaceItemAvatar,
|
||||
// WorkspaceItemWrapper,
|
||||
// WorkspaceItemContent,
|
||||
// } from '../styles';
|
||||
// import { FooterSetting } from './FooterSetting';
|
||||
// import { FooterUsers } from './FooterUsers';
|
||||
// import { WorkspaceType } from '@affine/datacenter';
|
||||
// import { useAppState } from '@/providers/app-state-provider';
|
||||
|
||||
interface WorkspaceItemProps {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
type: WorkspaceType;
|
||||
memberCount: number;
|
||||
onClickSetting?: (workspaceId: string) => void;
|
||||
}
|
||||
// interface WorkspaceItemProps {
|
||||
// id: string;
|
||||
// name: string;
|
||||
// icon: string;
|
||||
// type: WorkspaceType;
|
||||
// memberCount: number;
|
||||
// onClickSetting?: (workspaceId: string) => void;
|
||||
// }
|
||||
|
||||
export const WorkspaceItem = ({
|
||||
id,
|
||||
name,
|
||||
icon,
|
||||
type,
|
||||
onClickSetting,
|
||||
memberCount,
|
||||
}: WorkspaceItemProps) => {
|
||||
const router = useRouter();
|
||||
// export const WorkspaceItem = ({
|
||||
// id,
|
||||
// name,
|
||||
// icon,
|
||||
// type,
|
||||
// onClickSetting,
|
||||
// memberCount,
|
||||
// }: WorkspaceItemProps) => {
|
||||
// const router = useRouter();
|
||||
|
||||
const { currentWorkspaceId } = useAppState();
|
||||
// const { currentWorkspaceId } = useAppState();
|
||||
|
||||
const handleClickSetting = async () => {
|
||||
onClickSetting && onClickSetting(id);
|
||||
};
|
||||
// const handleClickSetting = async () => {
|
||||
// onClickSetting && onClickSetting(id);
|
||||
// };
|
||||
|
||||
return (
|
||||
<StyledWrapper
|
||||
onClick={() => {
|
||||
router.push(`/workspace/${id}`);
|
||||
}}
|
||||
canSet={
|
||||
type !== WorkspaceType.Private && currentWorkspaceId === String(id)
|
||||
}
|
||||
>
|
||||
<WorkspaceItemAvatar alt={name} src={icon}>
|
||||
{name.charAt(0)}
|
||||
</WorkspaceItemAvatar>
|
||||
<WorkspaceItemContent>
|
||||
<Name title={name}>{name}</Name>
|
||||
</WorkspaceItemContent>
|
||||
<Footer>
|
||||
<FooterUsers memberCount={memberCount} />
|
||||
<FooterSetting onClick={handleClickSetting} />
|
||||
</Footer>
|
||||
</StyledWrapper>
|
||||
);
|
||||
// return (
|
||||
// <StyledWrapper
|
||||
// onClick={() => {
|
||||
// router.push(`/workspace/${id}`);
|
||||
// }}
|
||||
// canSet={
|
||||
// type !== WorkspaceType.Private && currentWorkspaceId === String(id)
|
||||
// }
|
||||
// >
|
||||
// <WorkspaceItemAvatar alt={name} src={icon}>
|
||||
// {name.charAt(0)}
|
||||
// </WorkspaceItemAvatar>
|
||||
// <WorkspaceItemContent>
|
||||
// <Name title={name}>{name}</Name>
|
||||
// </WorkspaceItemContent>
|
||||
// <Footer>
|
||||
// <FooterUsers memberCount={memberCount} />
|
||||
// <FooterSetting onClick={handleClickSetting} />
|
||||
// </Footer>
|
||||
// </StyledWrapper>
|
||||
// );
|
||||
// };
|
||||
|
||||
// const Name = styled('div')(({ theme }) => {
|
||||
// return {
|
||||
// color: theme.colors.quoteColor,
|
||||
// fontSize: theme.font.sm,
|
||||
// fontWeight: 400,
|
||||
// overflow: 'hidden',
|
||||
// textOverflow: 'ellipsis',
|
||||
// whiteSpace: 'nowrap',
|
||||
// };
|
||||
// });
|
||||
|
||||
// const StyledWrapper = styled(WorkspaceItemWrapper)<{ canSet: boolean }>(
|
||||
// ({ canSet }) => {
|
||||
// return {
|
||||
// '& .footer-setting': {
|
||||
// display: 'none',
|
||||
// },
|
||||
// ':hover .footer-users': {
|
||||
// display: canSet ? 'none' : '',
|
||||
// },
|
||||
// ':hover .footer-setting': {
|
||||
// display: canSet ? 'block' : 'none',
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
// );
|
||||
|
||||
// const Footer = styled('div')({
|
||||
// width: '42px',
|
||||
// flex: '0 42px',
|
||||
// fontSize: '20px',
|
||||
// display: 'flex',
|
||||
// alignItems: 'center',
|
||||
// justifyContent: 'center',
|
||||
// marginLeft: '12px',
|
||||
// });
|
||||
|
||||
export const test = () => {
|
||||
return <></>;
|
||||
};
|
||||
|
||||
const Name = styled('div')(({ theme }) => {
|
||||
return {
|
||||
color: theme.colors.quoteColor,
|
||||
fontSize: theme.font.sm,
|
||||
fontWeight: 400,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
};
|
||||
});
|
||||
|
||||
const StyledWrapper = styled(WorkspaceItemWrapper)<{ canSet: boolean }>(
|
||||
({ canSet }) => {
|
||||
return {
|
||||
'& .footer-setting': {
|
||||
display: 'none',
|
||||
},
|
||||
':hover .footer-users': {
|
||||
display: canSet ? 'none' : '',
|
||||
},
|
||||
':hover .footer-setting': {
|
||||
display: canSet ? 'block' : 'none',
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const Footer = styled('div')({
|
||||
width: '42px',
|
||||
flex: '0 42px',
|
||||
fontSize: '20px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginLeft: '12px',
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
export * from './PrivateWorkspaceItem';
|
||||
export * from './WorkspaceItem';
|
||||
// export * from './WorkspaceItem';
|
||||
export * from './CreateWorkspaceItem';
|
||||
export * from './ListItem';
|
||||
export * from './LoginItem';
|
||||
|
||||
+8
-8
@@ -2,17 +2,16 @@ import { Avatar, WorkspaceName, SelectorWrapper } from './styles';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { WorkspaceModal } from '@/components/workspace-modal';
|
||||
import { WorkspaceAvatar } from '@/components/workspace-avatar';
|
||||
import { useTemporaryHelper } from '@/providers/temporary-helper-provider';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
export const WorkspaceSelector = () => {
|
||||
const [workspaceListShow, setWorkspaceListShow] = useState(false);
|
||||
const { currentWorkspace, workspaceMetaList } = useTemporaryHelper();
|
||||
const { currentMetaWorkSpace, workspaceList } = useAppState();
|
||||
|
||||
useEffect(() => {
|
||||
if (workspaceMetaList.length === 0) {
|
||||
if (workspaceList.length === 0) {
|
||||
setWorkspaceListShow(true);
|
||||
}
|
||||
}, [workspaceMetaList]);
|
||||
|
||||
}, [workspaceList]);
|
||||
return (
|
||||
<>
|
||||
<SelectorWrapper
|
||||
@@ -24,7 +23,7 @@ export const WorkspaceSelector = () => {
|
||||
<Avatar
|
||||
alt="Affine"
|
||||
data-testid="workspace-avatar"
|
||||
src={currentWorkspace?.avatar}
|
||||
src={currentMetaWorkSpace?.avatar}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
@@ -33,12 +32,13 @@ export const WorkspaceSelector = () => {
|
||||
>
|
||||
<WorkspaceAvatar
|
||||
size={28}
|
||||
name={currentWorkspace?.name ?? 'AFFiNE'}
|
||||
name={currentMetaWorkSpace?.name ?? 'AFFiNE'}
|
||||
avatar={currentMetaWorkSpace?.avatar ?? ''}
|
||||
/>
|
||||
</div>
|
||||
</Avatar>
|
||||
<WorkspaceName data-testid="workspace-name">
|
||||
{currentWorkspace?.name ?? 'AFFiNE'}
|
||||
{currentMetaWorkSpace?.name ?? 'AFFiNE'}
|
||||
</WorkspaceName>
|
||||
</SelectorWrapper>
|
||||
<WorkspaceModal
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
StyledArrowButton,
|
||||
StyledLink,
|
||||
StyledListItem,
|
||||
StyledListItemForWorkspace,
|
||||
// StyledListItemForWorkspace,
|
||||
StyledNewPageButton,
|
||||
StyledSliderBar,
|
||||
@@ -26,13 +27,14 @@ import {
|
||||
import Link from 'next/link';
|
||||
import { Tooltip } from '@/ui/tooltip';
|
||||
import { useModal } from '@/providers/GlobalModalProvider';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { IconButton } from '@/ui/button';
|
||||
import useLocalStorage from '@/hooks/use-local-storage';
|
||||
import usePageMetaList from '@/hooks/use-page-meta-list';
|
||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||
import { WorkspaceSetting } from '@/components/workspace-setting';
|
||||
// import { WorkspaceSetting } from '@/components/workspace-setting';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { WorkspaceSelector } from './WorkspaceSelector/WorkspaceSelector';
|
||||
|
||||
const FavoriteList = ({ showList }: { showList: boolean }) => {
|
||||
const { openPage } = usePageHelper();
|
||||
@@ -76,14 +78,15 @@ export const WorkSpaceSliderBar = () => {
|
||||
const [showTip, setShowTip] = useState(false);
|
||||
const [show, setShow] = useLocalStorage('AFFiNE_SLIDE_BAR', false, true);
|
||||
|
||||
const [showWorkspaceSetting, setShowWorkspaceSetting] = useState(false);
|
||||
|
||||
const paths = {
|
||||
all: currentWorkspaceId ? `/workspace/${currentWorkspaceId}/all` : '',
|
||||
favorite: currentWorkspaceId
|
||||
? `/workspace/${currentWorkspaceId}/favorite`
|
||||
: '',
|
||||
trash: currentWorkspaceId ? `/workspace/${currentWorkspaceId}/trash` : '',
|
||||
setting: currentWorkspaceId
|
||||
? `/workspace/${currentWorkspaceId}/setting`
|
||||
: '',
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -113,9 +116,9 @@ export const WorkSpaceSliderBar = () => {
|
||||
</Tooltip>
|
||||
|
||||
<StyledSliderBarWrapper data-testid="sliderBar">
|
||||
{/* <StyledListItemForWorkspace>
|
||||
<StyledListItemForWorkspace>
|
||||
<WorkspaceSelector />
|
||||
</StyledListItemForWorkspace> */}
|
||||
</StyledListItemForWorkspace>
|
||||
<StyledListItem
|
||||
data-testid="sliderBar-quickSearchButton"
|
||||
style={{ cursor: 'pointer' }}
|
||||
@@ -150,20 +153,19 @@ export const WorkSpaceSliderBar = () => {
|
||||
</IconButton>
|
||||
</StyledListItem>
|
||||
<FavoriteList showList={showSubFavorite} />
|
||||
<StyledListItem
|
||||
onClick={() => {
|
||||
setShowWorkspaceSetting(true);
|
||||
}}
|
||||
>
|
||||
<SettingsIcon /> Setting
|
||||
<StyledListItem active={router.asPath === paths.setting}>
|
||||
<StyledLink href={{ pathname: paths.setting }}>
|
||||
<SettingsIcon />
|
||||
Settings
|
||||
</StyledLink>
|
||||
</StyledListItem>
|
||||
|
||||
<WorkspaceSetting
|
||||
{/* <WorkspaceSetting
|
||||
isShow={showWorkspaceSetting}
|
||||
onClose={() => {
|
||||
setShowWorkspaceSetting(false);
|
||||
}}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
<StyledListItem
|
||||
onClick={() => {
|
||||
|
||||
@@ -7,22 +7,19 @@ const defaultOutLineWorkspaceId = 'affine';
|
||||
// Cause it not just ensure workspace loaded, but also have router change.
|
||||
export const useEnsureWorkspace = () => {
|
||||
const [workspaceLoaded, setWorkspaceLoaded] = useState(false);
|
||||
const { workspacesMeta, loadWorkspace, synced, user } = useAppState();
|
||||
const { workspaceList, loadWorkspace, user } = useAppState();
|
||||
console.log('workspaceList: ', workspaceList);
|
||||
const router = useRouter();
|
||||
|
||||
// const defaultOutLineWorkspaceId = '99ce7eb7';
|
||||
// console.log(defaultOutLineWorkspaceId);
|
||||
useEffect(() => {
|
||||
if (!synced) {
|
||||
setWorkspaceLoaded(false);
|
||||
return;
|
||||
}
|
||||
// If router.query.workspaceId is not in workspace list, jump to 404 page
|
||||
// If workspacesMeta is empty, we need to create a default workspace but not jump to 404
|
||||
// If workspaceList is empty, we need to create a default workspace but not jump to 404
|
||||
if (
|
||||
workspacesMeta.length &&
|
||||
workspaceList.length &&
|
||||
router.query.workspaceId &&
|
||||
workspacesMeta.findIndex(
|
||||
workspaceList.findIndex(
|
||||
meta => meta.id.toString() === router.query.workspaceId
|
||||
) === -1
|
||||
) {
|
||||
@@ -40,13 +37,13 @@ export const useEnsureWorkspace = () => {
|
||||
// }
|
||||
|
||||
const workspaceId = user
|
||||
? (router.query.workspaceId as string) || workspacesMeta[0]?.id
|
||||
? (router.query.workspaceId as string) || workspaceList[0]?.id
|
||||
: (router.query.workspaceId as string) || defaultOutLineWorkspaceId;
|
||||
|
||||
loadWorkspace(workspaceId).finally(() => {
|
||||
setWorkspaceLoaded(true);
|
||||
});
|
||||
}, [loadWorkspace, router, synced, user, workspacesMeta]);
|
||||
}, [loadWorkspace, router, user, workspaceList]);
|
||||
|
||||
return {
|
||||
workspaceLoaded,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
export const useInitWorkspace = (disabled?: boolean) => {
|
||||
@@ -8,15 +8,11 @@ export const useInitWorkspace = (disabled?: boolean) => {
|
||||
const defaultOutLineWorkspaceId = useRef(new Date().getTime().toString());
|
||||
|
||||
const router = useRouter();
|
||||
const {
|
||||
workspacesMeta,
|
||||
loadWorkspace,
|
||||
currentWorkspace,
|
||||
currentWorkspaceId,
|
||||
} = useAppState();
|
||||
const { workspaceList, loadWorkspace, currentWorkspace, currentWorkspaceId } =
|
||||
useAppState();
|
||||
const workspaceId =
|
||||
(router.query.workspaceId as string) ||
|
||||
workspacesMeta?.[0]?.id ||
|
||||
workspaceList?.[0]?.id ||
|
||||
defaultOutLineWorkspaceId.current;
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { User } from '@affine/datacenter';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const useUserHelper = () => {
|
||||
const { dataCenter } = useAppState();
|
||||
const [user, setUser] = useState<User | undefined>(undefined);
|
||||
useEffect(() => {
|
||||
dataCenter
|
||||
.getUserInfo()
|
||||
.then(user => {
|
||||
setUser(user);
|
||||
})
|
||||
.catch(e => {
|
||||
setUser(undefined);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const login = async () => {
|
||||
await dataCenter.login();
|
||||
const user = await dataCenter.getUserInfo();
|
||||
setUser(user);
|
||||
};
|
||||
return {
|
||||
user,
|
||||
login,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { Workspace } from '@blocksuite/store';
|
||||
export const useWorkspaceHelper = () => {
|
||||
const { dataCenter } = useAppState();
|
||||
const createWorkspace = async (name: string) => {
|
||||
const workspaceInfo = await dataCenter.createWorkspace({
|
||||
name: name,
|
||||
});
|
||||
if (workspaceInfo && workspaceInfo.room) {
|
||||
const workspace = await dataCenter.loadWorkspace(workspaceInfo.room);
|
||||
return workspace;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// const updateWorkspace = async (workspace: Workspace) => {};
|
||||
|
||||
const publishWorkspace = async (workspaceId: string, publish: boolean) => {
|
||||
dataCenter.setWorkspacePublish(workspaceId, publish);
|
||||
};
|
||||
|
||||
const updateWorkspace = async (
|
||||
{ name, avatarBlob }: { name?: string; avatarBlob?: Blob },
|
||||
workspace: Workspace
|
||||
) => {
|
||||
if (name) {
|
||||
await dataCenter.updateWorkspaceMeta({ name }, workspace);
|
||||
}
|
||||
if (avatarBlob) {
|
||||
const blobId = await dataCenter.setBlob(workspace, avatarBlob);
|
||||
await dataCenter.updateWorkspaceMeta({ avatar: blobId }, workspace);
|
||||
}
|
||||
};
|
||||
|
||||
const enableWorkspace = async (workspace: Workspace) => {
|
||||
const newWorkspaceId = await dataCenter.enableWorkspaceCloud(workspace);
|
||||
// console.log('newWorkspace: ', newWorkspace);
|
||||
return newWorkspaceId;
|
||||
};
|
||||
return {
|
||||
createWorkspace,
|
||||
publishWorkspace,
|
||||
updateWorkspace,
|
||||
enableWorkspace,
|
||||
};
|
||||
};
|
||||
@@ -1,4 +1,9 @@
|
||||
import NotfoundPage from '@/components/404';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
|
||||
export default function Custom404() {
|
||||
const { workspaceList } = useAppState();
|
||||
console.log('workspaceList: ', workspaceList);
|
||||
|
||||
return <NotfoundPage></NotfoundPage>;
|
||||
}
|
||||
|
||||
@@ -10,16 +10,18 @@ import '../utils/print-build-info';
|
||||
import ProviderComposer from '@/components/provider-composer';
|
||||
import type { PropsWithChildren, ReactElement, ReactNode } from 'react';
|
||||
import type { NextPage } from 'next';
|
||||
import { AppStateProvider } from '@/providers/app-state-provider/Provider';
|
||||
import { AppStateProvider } from '@/providers/app-state-provider';
|
||||
import ConfirmProvider from '@/providers/ConfirmProvider';
|
||||
import { ModalProvider } from '@/providers/GlobalModalProvider';
|
||||
// import AppStateProvider2 from '@/providers/app-state-provider2/provider';
|
||||
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { PageLoading } from '@/components/loading';
|
||||
import Head from 'next/head';
|
||||
import TemporaryHelperProvider from '@/providers/temporary-helper-provider';
|
||||
import '@affine/i18n';
|
||||
import TemporaryHelperProvider from '@/providers/temporary-helper-provider';
|
||||
|
||||
const ThemeProvider = dynamic(() => import('@/providers/ThemeProvider'), {
|
||||
ssr: false,
|
||||
@@ -56,6 +58,7 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => {
|
||||
<TemporaryHelperProvider key="TemporaryHelperProvider" />,
|
||||
<ThemeProvider key="ThemeProvider" />,
|
||||
<AppStateProvider key="appStateProvider" />,
|
||||
// <AppStateProvider2 key="appStateProvider2" />,
|
||||
<ModalProvider key="ModalProvider" />,
|
||||
<ConfirmProvider key="ConfirmProvider" />,
|
||||
]}
|
||||
@@ -67,9 +70,8 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => {
|
||||
};
|
||||
|
||||
const AppDefender = ({ children }: PropsWithChildren) => {
|
||||
const router = useRouter();
|
||||
|
||||
const { synced } = useAppState();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (router.pathname === '/') {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { styled } from '@/styles';
|
||||
import { Empty } from '@/ui/empty';
|
||||
import { Avatar } from '@mui/material';
|
||||
import { getDataCenter } from '@affine/datacenter';
|
||||
// import { getDataCenter } from '@affine/datacenter';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
@@ -37,6 +37,8 @@ export default function DevPage() {
|
||||
// .catch(err => {
|
||||
// console.log('err: ', err);
|
||||
// });
|
||||
setSuccessInvited(true);
|
||||
setInviteData(null);
|
||||
}, [router.query.invite_code]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,7 +4,7 @@ import exampleMarkdown1 from '@/templates/Welcome-to-the-AFFiNE-Alpha.md';
|
||||
import exampleMarkdown2 from '@/templates/AFFiNE-Docs.md';
|
||||
|
||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { Button } from '@/ui/button';
|
||||
interface Template {
|
||||
name: string;
|
||||
|
||||
@@ -2,88 +2,42 @@
|
||||
import {
|
||||
PropsWithChildren,
|
||||
ReactElement,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { styled } from '@/styles';
|
||||
import { EditorHeader } from '@/components/header';
|
||||
import EdgelessToolbar from '@/components/edgeless-toolbar';
|
||||
import MobileModal from '@/components/mobile-modal';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import exampleMarkdown from '@/templates/Welcome-to-AFFiNE-Alpha-v2.0.md';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import type { NextPageWithLayout } from '../..//_app';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
import { useRouter } from 'next/router';
|
||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||
|
||||
const StyledEditorContainer = styled('div')(() => {
|
||||
return {
|
||||
height: 'calc(100vh - 60px)',
|
||||
padding: '0 32px',
|
||||
};
|
||||
import dynamic from 'next/dynamic';
|
||||
import { EditorContainer } from '@blocksuite/editor';
|
||||
const DynamicBlocksuite = dynamic(() => import('@/components/editor'), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const Page: NextPageWithLayout = () => {
|
||||
const editorContainer = useRef<HTMLDivElement>(null);
|
||||
const { createEditor, setEditor, currentPage, currentWorkspace } =
|
||||
useAppState();
|
||||
|
||||
useEffect(() => {
|
||||
const ret = () => {
|
||||
const node = editorContainer.current;
|
||||
while (node?.firstChild) {
|
||||
node.removeChild(node.firstChild);
|
||||
}
|
||||
};
|
||||
|
||||
const editor = createEditor?.current?.(currentPage!);
|
||||
if (editor) {
|
||||
editorContainer.current?.appendChild(editor);
|
||||
setEditor?.current?.(editor);
|
||||
if (currentPage!.isEmpty) {
|
||||
const isFirstPage = currentWorkspace?.meta.pageMetas.length === 1;
|
||||
// Can not use useCurrentPageMeta to get new title, cause meta title will trigger rerender, but the second time can not remove title
|
||||
const { title: metaTitle } = currentPage!.meta;
|
||||
const title = metaTitle
|
||||
? metaTitle
|
||||
: isFirstPage
|
||||
? 'Welcome to AFFiNE Alpha "Abbey Wood"'
|
||||
: '';
|
||||
currentWorkspace?.setPageMeta(currentPage!.id, { title });
|
||||
|
||||
const pageId = currentPage!.addBlock({
|
||||
flavour: 'affine:page',
|
||||
title,
|
||||
});
|
||||
currentPage!.addBlock({ flavour: 'affine:surface' }, null);
|
||||
const frameId = currentPage!.addBlock(
|
||||
{ flavour: 'affine:frame' },
|
||||
pageId
|
||||
);
|
||||
currentPage!.addBlock({ flavour: 'affine:frame' }, pageId);
|
||||
// If this is a first page in workspace, init an introduction markdown
|
||||
if (isFirstPage) {
|
||||
editor.clipboard
|
||||
.importMarkdown(exampleMarkdown, `${frameId}`)
|
||||
.then(() => {
|
||||
currentWorkspace!.setPageMeta(currentPage!.id, { title });
|
||||
currentPage!.resetHistory();
|
||||
});
|
||||
}
|
||||
currentPage!.resetHistory();
|
||||
}
|
||||
}
|
||||
|
||||
document.title = currentPage?.meta.title || 'Untitled';
|
||||
return ret;
|
||||
}, [currentWorkspace, currentPage, createEditor, setEditor]);
|
||||
const { currentPage, currentWorkspace, setEditor } = useAppState();
|
||||
|
||||
const setEditorHandler = useCallback(
|
||||
(editor: EditorContainer) => setEditor.current(editor),
|
||||
[setEditor]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<EditorHeader />
|
||||
<MobileModal />
|
||||
<StyledEditorContainer ref={editorContainer} />
|
||||
|
||||
{currentPage && (
|
||||
<DynamicBlocksuite
|
||||
page={currentPage}
|
||||
workspace={currentWorkspace}
|
||||
setEditor={setEditorHandler}
|
||||
/>
|
||||
)}
|
||||
<EdgelessToolbar />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import useEnsureWorkspace from '@/hooks/use-ensure-workspace';
|
||||
import { PageLoading } from '@/components/loading';
|
||||
import usePageHelper from '@/hooks/use-page-helper';
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import {
|
||||
StyledSettingContainer,
|
||||
StyledSettingContent,
|
||||
StyledSettingSidebar,
|
||||
StyledSettingSidebarHeader,
|
||||
StyledSettingTabContainer,
|
||||
StyledSettingTagIconContainer,
|
||||
WorkspaceSettingTagItem,
|
||||
} from '@/components/workspace-setting/style';
|
||||
import {
|
||||
EditIcon,
|
||||
UsersIcon,
|
||||
PublishIcon,
|
||||
CloudInsyncIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { ReactElement, ReactNode, useState } from 'react';
|
||||
import {
|
||||
GeneralPage,
|
||||
MembersPage,
|
||||
PublishPage,
|
||||
ExportPage,
|
||||
SyncPage,
|
||||
} from '@/components/workspace-setting';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
import { WorkspaceInfo } from '@affine/datacenter';
|
||||
|
||||
type TabNames = 'general' | 'members' | 'publish' | 'sync' | 'export';
|
||||
|
||||
const tabMap: {
|
||||
name: TabNames;
|
||||
icon: ReactNode;
|
||||
panelRender: (workspace: WorkspaceInfo) => ReactNode;
|
||||
}[] = [
|
||||
{
|
||||
name: 'general',
|
||||
icon: <EditIcon />,
|
||||
panelRender: workspace => <GeneralPage workspace={workspace} />,
|
||||
},
|
||||
{
|
||||
name: 'members',
|
||||
icon: <CloudInsyncIcon />,
|
||||
panelRender: workspace => <MembersPage workspace={workspace} />,
|
||||
},
|
||||
{
|
||||
name: 'publish',
|
||||
icon: <UsersIcon />,
|
||||
panelRender: workspace => <PublishPage workspace={workspace} />,
|
||||
},
|
||||
{
|
||||
name: 'sync',
|
||||
icon: <PublishIcon />,
|
||||
panelRender: workspace => <SyncPage workspace={workspace} />,
|
||||
},
|
||||
{
|
||||
name: 'export',
|
||||
icon: <PublishIcon />,
|
||||
panelRender: workspace => <ExportPage workspace={workspace} />,
|
||||
},
|
||||
];
|
||||
|
||||
const WorkspaceSetting = () => {
|
||||
const { currentMetaWorkSpace } = useAppState();
|
||||
|
||||
const [activeTab, setActiveTab] = useState<TabNames>(tabMap[0].name);
|
||||
const handleTabChange = (tab: TabNames) => {
|
||||
setActiveTab(tab);
|
||||
};
|
||||
|
||||
const activeTabPanelRender = tabMap.find(
|
||||
tab => tab.name === activeTab
|
||||
)?.panelRender;
|
||||
|
||||
return (
|
||||
<StyledSettingContainer>
|
||||
<StyledSettingSidebar>
|
||||
<StyledSettingSidebarHeader>
|
||||
Workspace Settings
|
||||
</StyledSettingSidebarHeader>
|
||||
<StyledSettingTabContainer>
|
||||
{tabMap.map(({ icon, name }) => {
|
||||
return (
|
||||
<WorkspaceSettingTagItem
|
||||
key={name}
|
||||
isActive={activeTab === name}
|
||||
onClick={() => {
|
||||
handleTabChange(name);
|
||||
}}
|
||||
>
|
||||
<StyledSettingTagIconContainer>
|
||||
{icon}
|
||||
</StyledSettingTagIconContainer>
|
||||
{name}
|
||||
</WorkspaceSettingTagItem>
|
||||
);
|
||||
})}
|
||||
</StyledSettingTabContainer>
|
||||
</StyledSettingSidebar>
|
||||
|
||||
<StyledSettingContent>
|
||||
{currentMetaWorkSpace && activeTabPanelRender?.(currentMetaWorkSpace)}
|
||||
</StyledSettingContent>
|
||||
</StyledSettingContainer>
|
||||
);
|
||||
};
|
||||
WorkspaceSetting.getLayout = function getLayout(page: ReactElement) {
|
||||
return <WorkspaceLayout>{page}</WorkspaceLayout>;
|
||||
};
|
||||
|
||||
export default WorkspaceSetting;
|
||||
@@ -1,25 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import '@blocksuite/blocks';
|
||||
import { EditorContainer } from '@blocksuite/editor';
|
||||
import type { CreateEditorHandler } from './context';
|
||||
|
||||
interface Props {
|
||||
setCreateEditorHandler: (handler: CreateEditorHandler) => void;
|
||||
}
|
||||
|
||||
const DynamicBlocksuite = ({ setCreateEditorHandler }: Props) => {
|
||||
useEffect(() => {
|
||||
const createEditorHandler: CreateEditorHandler = (page: Page) => {
|
||||
const editor = new EditorContainer();
|
||||
editor.page = page;
|
||||
return editor;
|
||||
};
|
||||
|
||||
setCreateEditorHandler(createEditorHandler);
|
||||
}, [setCreateEditorHandler]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
export default DynamicBlocksuite;
|
||||
@@ -1,143 +1,144 @@
|
||||
import { useMemo, useState, useCallback, useRef } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { createContext, useContext, useEffect, useState, useRef } from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { getDataCenter } from '@affine/datacenter';
|
||||
import { AppState, AppStateContext } from './context';
|
||||
import type {
|
||||
import {
|
||||
AppStateContext,
|
||||
AppStateFunction,
|
||||
AppStateValue,
|
||||
CreateEditorHandler,
|
||||
LoadWorkspaceHandler,
|
||||
} from './context';
|
||||
import { Page } from '@blocksuite/store';
|
||||
import { EditorContainer } from '@blocksuite/editor';
|
||||
const DynamicBlocksuite = dynamic(() => import('./DynamicBlocksuite'), {
|
||||
ssr: false,
|
||||
});
|
||||
PageMeta,
|
||||
} from './interface';
|
||||
import { createDefaultWorkspace } from './utils';
|
||||
import { WorkspaceInfo } from '@affine/datacenter';
|
||||
|
||||
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();
|
||||
const workspacesMeta = await dc.apis.getWorkspaces().catch(() => {
|
||||
return [];
|
||||
type AppStateContextProps = PropsWithChildren<Record<string, unknown>>;
|
||||
|
||||
export const AppState = createContext<AppStateContext>({} as AppStateContext);
|
||||
|
||||
export const useAppState = () => useContext(AppState);
|
||||
|
||||
export const AppStateProvider = ({
|
||||
children,
|
||||
}: PropsWithChildren<AppStateContextProps>) => {
|
||||
const [appState, setAppState] = useState<AppStateValue>({} as AppStateValue);
|
||||
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
const dataCenter = await getDataCenter();
|
||||
|
||||
if (dataCenter.workspaces.length === 0) {
|
||||
await createDefaultWorkspace(dataCenter);
|
||||
}
|
||||
const currentWorkspace = await dataCenter.loadWorkspace(
|
||||
dataCenter.workspaces[0].id
|
||||
);
|
||||
const currentMetaWorkSpace = dataCenter.workspaces.find(item => {
|
||||
return item.id === currentWorkspace.room;
|
||||
});
|
||||
|
||||
setAppState({
|
||||
dataCenter,
|
||||
user: (await dataCenter.getUserInfo()) || null,
|
||||
workspaceList: dataCenter.workspaces,
|
||||
currentWorkspaceId: dataCenter.workspaces[0].id,
|
||||
currentWorkspace,
|
||||
pageList: currentWorkspace.meta.pageMetas as PageMeta[],
|
||||
currentPage: null,
|
||||
editor: null,
|
||||
synced: true,
|
||||
currentMetaWorkSpace: currentMetaWorkSpace ?? null,
|
||||
});
|
||||
};
|
||||
|
||||
init();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!appState?.currentWorkspace) {
|
||||
return;
|
||||
}
|
||||
const currentWorkspace = appState.currentWorkspace;
|
||||
const dispose = currentWorkspace.meta.pagesUpdated.on(() => {
|
||||
setAppState({
|
||||
...appState,
|
||||
pageList: currentWorkspace.meta.pageMetas as PageMeta[],
|
||||
});
|
||||
}).dispose;
|
||||
return () => {
|
||||
dispose();
|
||||
};
|
||||
}, [appState]);
|
||||
|
||||
useEffect(() => {
|
||||
const { dataCenter } = appState;
|
||||
// FIXME: onWorkspacesChange should have dispose function
|
||||
dataCenter?.onWorkspacesChange(() => {
|
||||
setAppState({
|
||||
...appState,
|
||||
workspaceList: dataCenter.workspaces,
|
||||
});
|
||||
});
|
||||
}, [appState]);
|
||||
|
||||
const loadPage = useRef<AppStateFunction['loadPage']>();
|
||||
loadPage.current = (pageId: string) => {
|
||||
const { currentWorkspace, currentPage } = appState;
|
||||
if (pageId === currentPage?.id) {
|
||||
return;
|
||||
}
|
||||
const page = currentWorkspace?.getPage(pageId) || null;
|
||||
setAppState({
|
||||
...appState,
|
||||
currentPage: page,
|
||||
});
|
||||
setState(state => ({ ...state, workspacesMeta }));
|
||||
};
|
||||
|
||||
const [state, setState] = useState<AppStateValue>({
|
||||
user: null,
|
||||
workspacesMeta: [],
|
||||
currentWorkspaceId: '',
|
||||
currentWorkspace: null,
|
||||
currentPage: null,
|
||||
editor: null,
|
||||
refreshWorkspacesMeta,
|
||||
synced: true,
|
||||
});
|
||||
|
||||
const [createEditorHandler, _setCreateEditorHandler] =
|
||||
useState<CreateEditorHandler>();
|
||||
|
||||
const setCreateEditorHandler = useCallback(
|
||||
(handler: CreateEditorHandler) => {
|
||||
_setCreateEditorHandler(() => handler);
|
||||
},
|
||||
[_setCreateEditorHandler]
|
||||
);
|
||||
|
||||
const loadWorkspace = useRef<AppStateContext['loadWorkspace']>(() =>
|
||||
Promise.resolve(null)
|
||||
);
|
||||
const loadWorkspace = useRef<AppStateFunction['loadWorkspace']>();
|
||||
loadWorkspace.current = async (workspaceId: string) => {
|
||||
if (state.currentWorkspaceId === workspaceId) {
|
||||
return state.currentWorkspace;
|
||||
const { dataCenter, workspaceList, currentWorkspaceId, currentWorkspace } =
|
||||
appState;
|
||||
if (!workspaceList.find(v => v.id === workspaceId)) {
|
||||
return null;
|
||||
}
|
||||
const workspace =
|
||||
(await loadWorkspaceHandler(workspaceId, state.user)) || null;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
window.workspace = workspace;
|
||||
// FIXME: there needs some method to destroy websocket.
|
||||
// Or we need a manager to manage websocket.
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
state.currentWorkspace?.__ws__?.destroy();
|
||||
|
||||
setState(state => ({
|
||||
...state,
|
||||
if (workspaceId === currentWorkspaceId) {
|
||||
return currentWorkspace;
|
||||
}
|
||||
const workspace = await dataCenter.loadWorkspace(workspaceId);
|
||||
const currentMetaWorkSpace = dataCenter.workspaces.find(
|
||||
(item: WorkspaceInfo) => {
|
||||
return item.id === workspace.room;
|
||||
}
|
||||
);
|
||||
setAppState({
|
||||
...appState,
|
||||
currentWorkspace: workspace,
|
||||
currentWorkspaceId: workspaceId,
|
||||
}));
|
||||
currentMetaWorkSpace: currentMetaWorkSpace ?? null,
|
||||
pageList: currentWorkspace.meta.pageMetas as PageMeta[],
|
||||
currentPage: null,
|
||||
editor: null,
|
||||
});
|
||||
|
||||
return workspace;
|
||||
};
|
||||
|
||||
const loadPage = useRef<AppStateContext['loadPage']>(() =>
|
||||
Promise.resolve(null)
|
||||
);
|
||||
loadPage.current = async (pageId: string) => {
|
||||
const { currentWorkspace, currentPage } = state;
|
||||
if (pageId === currentPage?.id) {
|
||||
return currentPage;
|
||||
}
|
||||
const page = (pageId ? currentWorkspace?.getPage(pageId) : null) || null;
|
||||
setState(state => ({ ...state, currentPage: page }));
|
||||
return page;
|
||||
const setEditor: AppStateFunction['setEditor'] =
|
||||
useRef() as AppStateFunction['setEditor'];
|
||||
setEditor.current = editor => {
|
||||
setAppState({
|
||||
...appState,
|
||||
editor,
|
||||
});
|
||||
};
|
||||
|
||||
const createEditor = useRef<
|
||||
((page: Page) => EditorContainer | null) | undefined
|
||||
>();
|
||||
createEditor.current = () => {
|
||||
const { currentPage, currentWorkspace } = state;
|
||||
if (!currentPage || !currentWorkspace) {
|
||||
return null;
|
||||
}
|
||||
const editor = createEditorHandler?.(currentPage) || null;
|
||||
|
||||
if (editor) {
|
||||
const pageMeta = currentWorkspace.meta.pageMetas.find(
|
||||
p => p.id === currentPage.id
|
||||
);
|
||||
if (pageMeta?.mode) {
|
||||
editor.mode = pageMeta.mode as 'page' | 'edgeless' | undefined;
|
||||
}
|
||||
if (pageMeta?.trash) {
|
||||
editor.readonly = true;
|
||||
}
|
||||
}
|
||||
|
||||
return editor;
|
||||
};
|
||||
|
||||
const setEditor = useRef<(editor: AppStateValue['editor']) => void>();
|
||||
|
||||
setEditor.current = (editor: AppStateValue['editor']) => {
|
||||
setState(state => ({ ...state, editor }));
|
||||
};
|
||||
|
||||
const context = useMemo(
|
||||
() => ({
|
||||
...state,
|
||||
setState,
|
||||
createEditor,
|
||||
setEditor,
|
||||
loadWorkspace: loadWorkspace.current,
|
||||
loadPage: loadPage.current,
|
||||
}),
|
||||
[state, setState, loadPage, loadWorkspace]
|
||||
);
|
||||
|
||||
return (
|
||||
<AppState.Provider value={context}>
|
||||
<DynamicBlocksuite setCreateEditorHandler={setCreateEditorHandler} />
|
||||
<AppState.Provider
|
||||
value={{
|
||||
...appState,
|
||||
setEditor,
|
||||
loadPage: loadPage.current,
|
||||
loadWorkspace: loadWorkspace.current,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AppState.Provider>
|
||||
);
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import { createContext, MutableRefObject, useContext } from 'react';
|
||||
import type { AccessTokenMessage, Workspace } from '@affine/datacenter';
|
||||
import type {
|
||||
Page as StorePage,
|
||||
Workspace as StoreWorkspace,
|
||||
} from '@blocksuite/store';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
|
||||
export type LoadWorkspaceHandler = (
|
||||
workspaceId: string,
|
||||
user?: AccessTokenMessage | null
|
||||
) => Promise<StoreWorkspace | null> | null;
|
||||
export type CreateEditorHandler = (page: StorePage) => EditorContainer | null;
|
||||
|
||||
export interface AppStateValue {
|
||||
user: AccessTokenMessage | null;
|
||||
workspacesMeta: Workspace[];
|
||||
|
||||
currentWorkspaceId: string;
|
||||
currentWorkspace: StoreWorkspace | null;
|
||||
|
||||
currentPage: StorePage | null;
|
||||
|
||||
// workspaces: Record<string, StoreWorkspace | null>;
|
||||
|
||||
editor: EditorContainer | null;
|
||||
synced: boolean;
|
||||
refreshWorkspacesMeta: () => void;
|
||||
}
|
||||
|
||||
export interface AppStateContext extends AppStateValue {
|
||||
setState: (state: AppStateValue) => void;
|
||||
createEditor?: MutableRefObject<
|
||||
((page: StorePage) => EditorContainer | null) | undefined
|
||||
>;
|
||||
setEditor?: MutableRefObject<((page: EditorContainer) => void) | undefined>;
|
||||
loadWorkspace: (workspaceId: string) => Promise<StoreWorkspace | null>;
|
||||
loadPage: (pageId: string) => Promise<StorePage | null>;
|
||||
}
|
||||
|
||||
export const AppState = createContext<AppStateContext>({
|
||||
user: null,
|
||||
workspacesMeta: [],
|
||||
currentWorkspaceId: '',
|
||||
currentWorkspace: null,
|
||||
currentPage: null,
|
||||
editor: null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
setState: () => {},
|
||||
createEditor: undefined,
|
||||
setEditor: undefined,
|
||||
loadWorkspace: () => Promise.resolve(null),
|
||||
loadPage: () => Promise.resolve(null),
|
||||
synced: false,
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
refreshWorkspacesMeta: () => {},
|
||||
});
|
||||
|
||||
export const useAppState = () => {
|
||||
return useContext(AppState);
|
||||
};
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from './context';
|
||||
export * from './Provider';
|
||||
export * from './interface';
|
||||
|
||||
@@ -1,17 +1,40 @@
|
||||
import { PageMeta as OriginalPageMeta } from '@blocksuite/store/dist/workspace/workspace';
|
||||
import { DataCenter, User, WorkspaceInfo } from '@affine/datacenter';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
|
||||
// export type PageMeta = {
|
||||
// favorite: boolean;
|
||||
// trash: boolean;
|
||||
// trashDate: number | void;
|
||||
// updatedDate: number | void;
|
||||
// mode: EditorContainer['mode'];
|
||||
// } & OriginalPageMeta;
|
||||
|
||||
export interface PageMeta extends OriginalPageMeta {
|
||||
import type {
|
||||
Page as StorePage,
|
||||
Workspace as StoreWorkspace,
|
||||
PageMeta as StorePageMeta,
|
||||
} from '@blocksuite/store';
|
||||
import { MutableRefObject } from 'react';
|
||||
export interface PageMeta extends StorePageMeta {
|
||||
favorite: boolean;
|
||||
trash: boolean;
|
||||
trashDate: number;
|
||||
updatedDate: number;
|
||||
mode: 'edgeless' | 'page';
|
||||
}
|
||||
|
||||
export type AppStateValue = {
|
||||
dataCenter: DataCenter;
|
||||
user: User | null;
|
||||
workspaceList: WorkspaceInfo[];
|
||||
currentWorkspace: StoreWorkspace;
|
||||
currentMetaWorkSpace: WorkspaceInfo | null;
|
||||
currentWorkspaceId: string;
|
||||
pageList: PageMeta[];
|
||||
currentPage: StorePage | null;
|
||||
editor?: EditorContainer | null;
|
||||
synced: boolean;
|
||||
};
|
||||
|
||||
export type AppStateFunction = {
|
||||
setEditor: MutableRefObject<(page: EditorContainer) => void>;
|
||||
|
||||
loadWorkspace: (workspaceId: string) => Promise<StoreWorkspace | null>;
|
||||
loadPage: (pageId: string) => void;
|
||||
};
|
||||
|
||||
export type AppStateContext = AppStateValue & AppStateFunction;
|
||||
|
||||
export type CreateEditorHandler = (page: StorePage) => EditorContainer | null;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { DataCenter } from '@affine/datacenter';
|
||||
|
||||
const DEFAULT_WORKSPACE_NAME = 'affine';
|
||||
|
||||
export const createDefaultWorkspace = async (dataCenter: DataCenter) => {
|
||||
return dataCenter.createWorkspace({
|
||||
avatar: 'test',
|
||||
name: DEFAULT_WORKSPACE_NAME,
|
||||
});
|
||||
};
|
||||
@@ -37,8 +37,11 @@
|
||||
"ky-universal": "^0.11.0",
|
||||
"lib0": "^0.2.58",
|
||||
"swr": "^2.0.0",
|
||||
"vitest": "^0.26.3",
|
||||
"y-protocols": "^1.0.5",
|
||||
"yjs": "^13.5.44"
|
||||
"yjs": "^13.5.44",
|
||||
"y-protocols": "^1.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@blocksuite/blocks": "0.3.1-*",
|
||||
"@blocksuite/store": "0.3.1-*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { getLogger } from './logger';
|
||||
import { applyUpdate, encodeStateAsUpdate } from 'yjs';
|
||||
import { TauriIPCProvider } from './provider/tauri-ipc';
|
||||
import { createBlocksuiteWorkspace } from './utils/index.js';
|
||||
import { MessageCenter } from './message/message';
|
||||
import { MessageCenter } from './message';
|
||||
|
||||
/**
|
||||
* @class DataCenter
|
||||
@@ -313,6 +313,7 @@ export class DataCenter {
|
||||
applyUpdate(newWorkspace.doc, encodeStateAsUpdate(workspace.doc));
|
||||
assert(newWorkspace, 'Create workspace failed');
|
||||
await currentProvider.deleteWorkspace(workspace.room);
|
||||
return newWorkspace.room;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,8 @@ const _initializeDataCenter = () => {
|
||||
|
||||
export const getDataCenter = _initializeDataCenter();
|
||||
|
||||
export type { DataCenter };
|
||||
export type { AccessTokenMessage } from './provider/affine/apis';
|
||||
export type { WorkspaceInfo } from './types';
|
||||
export * from './types';
|
||||
export { getLogger } from './logger';
|
||||
export * from './message';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Observable } from 'lib0/observable';
|
||||
import { Message } from 'src/types';
|
||||
import { Message } from '../types';
|
||||
import { MessageCode } from './code';
|
||||
|
||||
export class MessageCenter extends Observable<string> {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { WebsocketProvider } from './sync.js';
|
||||
import { getApis } from './apis/index.js';
|
||||
import type { Apis, WorkspaceDetail, Callback } from './apis';
|
||||
import { setDefaultAvatar } from '../utils.js';
|
||||
import { MessageCode } from 'src/message/code.js';
|
||||
import { MessageCode } from '../../message';
|
||||
|
||||
export interface AffineProviderConstructorParams
|
||||
extends ProviderConstructorParams {
|
||||
@@ -146,8 +146,8 @@ export class AffineProvider extends BaseProvider {
|
||||
if (workspace) {
|
||||
workspaces[i] = {
|
||||
...workspaces[i],
|
||||
name: workspace.doc.meta.name,
|
||||
avatar: workspace.doc.meta.avatar,
|
||||
name: workspace.meta.name,
|
||||
avatar: workspace.meta.avatar,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Workspace as BlocksuiteWorkspace, uuidv4 } from '@blocksuite/store';
|
||||
import { MessageCenter } from 'src/message';
|
||||
import { MessageCenter } from '../message';
|
||||
import { Logger, User, WorkspaceInfo, WorkspaceMeta } from '../types';
|
||||
import type { WorkspaceMetaCollectionScope } from '../workspace-meta-collection';
|
||||
|
||||
|
||||
@@ -25,8 +25,9 @@ export class LocalProvider extends BaseProvider {
|
||||
public override async linkLocal(workspace: BlocksuiteWorkspace) {
|
||||
assert(workspace.room);
|
||||
let idb = this._idbMap.get(workspace.room);
|
||||
idb?.destroy();
|
||||
idb = new IndexedDBProvider(workspace.room, workspace.doc);
|
||||
if (!idb) {
|
||||
idb = new IndexedDBProvider(workspace.room, workspace.doc);
|
||||
}
|
||||
this._idbMap.set(workspace.room, idb);
|
||||
this._logger('Local data loaded');
|
||||
return workspace;
|
||||
|
||||
Generated
+101
-2514
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user