mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-15 00:56:26 +08:00
feat: new workspace switch dropdown design (#3700)
Co-authored-by: Alex Yang <himself65@outlook.com>
This commit is contained in:
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
Menu,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalCloseButton,
|
||||
ModalWrapper,
|
||||
Tooltip,
|
||||
} from '@affine/component';
|
||||
import { Menu, MenuItem, Tooltip } from '@affine/component';
|
||||
import { ScrollableContainer } from '@affine/component';
|
||||
import { WorkspaceList } from '@affine/component/workspace-list';
|
||||
import type {
|
||||
@@ -15,28 +8,38 @@ import type {
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
|
||||
import { HelpIcon, ImportIcon, PlusIcon } from '@blocksuite/icons';
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
import type { AllWorkspace } from '../../../shared';
|
||||
import { Footer } from '../footer';
|
||||
import {
|
||||
StyledCreateWorkspaceCard,
|
||||
CloudWorkspaceIcon,
|
||||
HelpIcon,
|
||||
ImportIcon,
|
||||
MoreHorizontalIcon,
|
||||
PlusIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import { Popover } from '@mui/material';
|
||||
import { IconButton } from '@toeverything/components/button';
|
||||
import { Divider } from '@toeverything/components/divider';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { openDisableCloudAlertModalAtom } from '../../../atoms';
|
||||
import type { AllWorkspace } from '../../../shared';
|
||||
import {
|
||||
StyledCreateWorkspaceCardPill,
|
||||
StyledCreateWorkspaceCardPillContainer,
|
||||
StyledCreateWorkspaceCardPillContent,
|
||||
StyledCreateWorkspaceCardPillIcon,
|
||||
StyledCreateWorkspaceCardPillTextSecondary,
|
||||
StyledHelperContainer,
|
||||
StyledImportWorkspaceCardPill,
|
||||
StyledModalBody,
|
||||
StyledModalContent,
|
||||
StyledModalHeader,
|
||||
StyledModalHeaderLeft,
|
||||
StyledModalTitle,
|
||||
StyledOperationWrapper,
|
||||
StyleWorkspaceAdd,
|
||||
StyleWorkspaceInfo,
|
||||
StyleWorkspaceTitle,
|
||||
StyledSignInCardPill,
|
||||
StyledSignInCardPillTextCotainer,
|
||||
StyledSignInCardPillTextPrimary,
|
||||
StyledSignInCardPillTextSecondary,
|
||||
} from './styles';
|
||||
|
||||
interface WorkspaceModalProps {
|
||||
@@ -52,105 +55,94 @@ interface WorkspaceModalProps {
|
||||
onMoveWorkspace: (activeId: string, overId: string) => void;
|
||||
}
|
||||
|
||||
const CreateWorkspaceCard = ({
|
||||
onNewWorkspace,
|
||||
onAddWorkspace,
|
||||
}: {
|
||||
onNewWorkspace: () => void;
|
||||
onAddWorkspace: () => void;
|
||||
}) => {
|
||||
const AccountMenu = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
const anchorEL = useRef<HTMLDivElement>(null);
|
||||
return (
|
||||
<div>
|
||||
<div>Unlimted</div>
|
||||
<Divider></Divider>
|
||||
<MenuItem icon={<ImportIcon />} data-testid="editor-option-menu-import">
|
||||
{t['com.affine.workspace.cloud.join']()}
|
||||
</MenuItem>
|
||||
<MenuItem icon={<ImportIcon />} data-testid="editor-option-menu-import">
|
||||
{t['com.affine.workspace.cloud.account.settings']()}
|
||||
</MenuItem>
|
||||
<Divider></Divider>
|
||||
<MenuItem icon={<ImportIcon />} data-testid="editor-option-menu-import">
|
||||
{t['com.affine.workspace.cloud.account.logout']()}
|
||||
</MenuItem>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
if (runtimeConfig.enableSQLiteProvider && environment.isDesktop) {
|
||||
return (
|
||||
<Menu
|
||||
placement="auto"
|
||||
trigger={['click']}
|
||||
zIndex={1000}
|
||||
content={
|
||||
<StyledCreateWorkspaceCardPillContainer>
|
||||
<StyledCreateWorkspaceCardPill>
|
||||
<MenuItem
|
||||
style={{
|
||||
height: 'auto',
|
||||
padding: '8px 12px',
|
||||
}}
|
||||
onClick={onNewWorkspace}
|
||||
data-testid="new-workspace"
|
||||
>
|
||||
<StyledCreateWorkspaceCardPillContent>
|
||||
<div>
|
||||
<p>{t['New Workspace']()}</p>
|
||||
<StyledCreateWorkspaceCardPillTextSecondary>
|
||||
<p>{t['Create your own workspace']()}</p>
|
||||
</StyledCreateWorkspaceCardPillTextSecondary>
|
||||
</div>
|
||||
<StyledCreateWorkspaceCardPillIcon>
|
||||
<PlusIcon />
|
||||
</StyledCreateWorkspaceCardPillIcon>
|
||||
</StyledCreateWorkspaceCardPillContent>
|
||||
</MenuItem>
|
||||
</StyledCreateWorkspaceCardPill>
|
||||
<StyledCreateWorkspaceCardPill>
|
||||
<MenuItem
|
||||
onClick={onAddWorkspace}
|
||||
data-testid="add-workspace"
|
||||
style={{
|
||||
height: 'auto',
|
||||
padding: '8px 12px',
|
||||
}}
|
||||
>
|
||||
<StyledCreateWorkspaceCardPillContent>
|
||||
<div>
|
||||
<p>{t['Add Workspace']()}</p>
|
||||
<StyledCreateWorkspaceCardPillTextSecondary>
|
||||
<p>{t['Add Workspace Hint']()}</p>
|
||||
</StyledCreateWorkspaceCardPillTextSecondary>
|
||||
</div>
|
||||
<StyledCreateWorkspaceCardPillIcon>
|
||||
<ImportIcon />
|
||||
</StyledCreateWorkspaceCardPillIcon>
|
||||
</StyledCreateWorkspaceCardPillContent>
|
||||
</MenuItem>
|
||||
</StyledCreateWorkspaceCardPill>
|
||||
</StyledCreateWorkspaceCardPillContainer>
|
||||
}
|
||||
>
|
||||
<StyledCreateWorkspaceCard
|
||||
ref={anchorEL}
|
||||
data-testid="add-or-new-workspace"
|
||||
>
|
||||
<StyleWorkspaceAdd className="add-icon">
|
||||
<PlusIcon />
|
||||
</StyleWorkspaceAdd>
|
||||
const CloudWorkSpaceList = ({
|
||||
disabled,
|
||||
workspaces,
|
||||
onClickWorkspace,
|
||||
onClickWorkspaceSetting,
|
||||
currentWorkspaceId,
|
||||
onMoveWorkspace,
|
||||
}: WorkspaceModalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
<StyleWorkspaceInfo>
|
||||
<StyleWorkspaceTitle>{t['New Workspace']()}</StyleWorkspaceTitle>
|
||||
<p>{t['Create Or Import']()}</p>
|
||||
</StyleWorkspaceInfo>
|
||||
</StyledCreateWorkspaceCard>
|
||||
</Menu>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<StyledCreateWorkspaceCard
|
||||
onClick={onNewWorkspace}
|
||||
data-testid="new-workspace"
|
||||
>
|
||||
<StyleWorkspaceAdd className="add-icon">
|
||||
<PlusIcon />
|
||||
</StyleWorkspaceAdd>
|
||||
return (
|
||||
<>
|
||||
<StyledModalHeader>
|
||||
<StyledModalHeaderLeft>
|
||||
<StyledModalTitle>
|
||||
{t['com.affine.workspace.cloud.sync']()}
|
||||
</StyledModalTitle>
|
||||
<Tooltip
|
||||
content={t['Workspace description']()}
|
||||
placement="top-start"
|
||||
disablePortal={true}
|
||||
>
|
||||
<StyledHelperContainer>
|
||||
<HelpIcon />
|
||||
</StyledHelperContainer>
|
||||
</Tooltip>
|
||||
</StyledModalHeaderLeft>
|
||||
|
||||
<StyleWorkspaceInfo>
|
||||
<StyleWorkspaceTitle>{t['New Workspace']()}</StyleWorkspaceTitle>
|
||||
<p>{t['Create Or Import']()}</p>
|
||||
</StyleWorkspaceInfo>
|
||||
</StyledCreateWorkspaceCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
<StyledOperationWrapper>
|
||||
<Menu
|
||||
placement="bottom-end"
|
||||
trigger={['click']}
|
||||
content={<AccountMenu />}
|
||||
zIndex={1000}
|
||||
>
|
||||
<IconButton
|
||||
data-testid="previous-image-button"
|
||||
icon={<MoreHorizontalIcon />}
|
||||
type="plain"
|
||||
/>
|
||||
</Menu>
|
||||
</StyledOperationWrapper>
|
||||
</StyledModalHeader>
|
||||
<StyledModalContent>
|
||||
<WorkspaceList
|
||||
disabled={disabled}
|
||||
items={
|
||||
workspaces.filter(
|
||||
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
|
||||
) as (AffineCloudWorkspace | LocalWorkspace)[]
|
||||
}
|
||||
currentWorkspaceId={currentWorkspaceId}
|
||||
onClick={onClickWorkspace}
|
||||
onSettingClick={onClickWorkspaceSetting}
|
||||
onDragEnd={useCallback(
|
||||
(event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
if (active.id !== over?.id) {
|
||||
onMoveWorkspace(active.id as string, over?.id as string);
|
||||
}
|
||||
},
|
||||
[onMoveWorkspace]
|
||||
)}
|
||||
/>
|
||||
<Divider />
|
||||
</StyledModalContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const WorkspaceListModal = ({
|
||||
@@ -166,19 +158,77 @@ export const WorkspaceListModal = ({
|
||||
onMoveWorkspace,
|
||||
}: WorkspaceModalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const setOpen = useSetAtom(openDisableCloudAlertModalAtom);
|
||||
// TODO: AFFiNE Cloud support
|
||||
const isLoggedIn = false;
|
||||
const anchorEl = document.getElementById('current-workspace');
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={onClose}>
|
||||
<ModalWrapper
|
||||
width={720}
|
||||
height={690}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<StyledModalHeader>
|
||||
<StyledModalHeaderLeft>
|
||||
<StyledModalTitle>{t['My Workspaces']()}</StyledModalTitle>
|
||||
<Popover
|
||||
sx={{
|
||||
color: 'success.main',
|
||||
zIndex: 999,
|
||||
'& .MuiPopover-paper': {
|
||||
borderRadius: '8px',
|
||||
boxShadow: 'var(--affine-shadow-1)',
|
||||
},
|
||||
}}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={onClose}
|
||||
>
|
||||
<StyledModalBody>
|
||||
<ScrollableContainer>
|
||||
{isLoggedIn ? (
|
||||
<CloudWorkSpaceList
|
||||
disabled={disabled}
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
workspaces={workspaces}
|
||||
onClickWorkspace={onClickWorkspace}
|
||||
onClickWorkspaceSetting={onClickWorkspaceSetting}
|
||||
onNewWorkspace={onNewWorkspace}
|
||||
onAddWorkspace={onAddWorkspace}
|
||||
currentWorkspaceId={currentWorkspaceId}
|
||||
onMoveWorkspace={onMoveWorkspace}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<StyledModalContent>
|
||||
<StyledSignInCardPill>
|
||||
<MenuItem
|
||||
style={{
|
||||
height: 'auto',
|
||||
padding: '8px 12px',
|
||||
}}
|
||||
onClick={async () => {
|
||||
if (!runtimeConfig.enableCloud) {
|
||||
setOpen(true);
|
||||
}
|
||||
}}
|
||||
data-testid="cloud-signin-button"
|
||||
>
|
||||
<StyledCreateWorkspaceCardPillContent>
|
||||
<StyledCreateWorkspaceCardPillIcon>
|
||||
<CloudWorkspaceIcon />
|
||||
</StyledCreateWorkspaceCardPillIcon>
|
||||
<StyledSignInCardPillTextCotainer>
|
||||
<StyledSignInCardPillTextPrimary>
|
||||
{t['com.affine.workspace.cloud.auth']()}
|
||||
</StyledSignInCardPillTextPrimary>
|
||||
<StyledSignInCardPillTextSecondary>
|
||||
Sync with AFFiNE Cloud
|
||||
</StyledSignInCardPillTextSecondary>
|
||||
</StyledSignInCardPillTextCotainer>
|
||||
</StyledCreateWorkspaceCardPillContent>
|
||||
</MenuItem>
|
||||
</StyledSignInCardPill>
|
||||
<Divider />
|
||||
</StyledModalContent>
|
||||
</>
|
||||
)}
|
||||
<StyledModalHeader>
|
||||
<StyledModalTitle>{t['Local Workspace']()}</StyledModalTitle>
|
||||
<Tooltip
|
||||
content={t['Workspace description']()}
|
||||
placement="top-start"
|
||||
@@ -188,19 +238,7 @@ export const WorkspaceListModal = ({
|
||||
<HelpIcon />
|
||||
</StyledHelperContainer>
|
||||
</Tooltip>
|
||||
</StyledModalHeaderLeft>
|
||||
|
||||
<StyledOperationWrapper>
|
||||
<ModalCloseButton
|
||||
data-testid="close-workspace-modal"
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
absolute={false}
|
||||
/>
|
||||
</StyledOperationWrapper>
|
||||
</StyledModalHeader>
|
||||
<ScrollableContainer>
|
||||
</StyledModalHeader>
|
||||
<StyledModalContent>
|
||||
<WorkspaceList
|
||||
disabled={disabled}
|
||||
@@ -222,14 +260,51 @@ export const WorkspaceListModal = ({
|
||||
[onMoveWorkspace]
|
||||
)}
|
||||
/>
|
||||
<CreateWorkspaceCard
|
||||
onNewWorkspace={onNewWorkspace}
|
||||
onAddWorkspace={onAddWorkspace}
|
||||
/>
|
||||
</StyledModalContent>
|
||||
<StyledModalContent>
|
||||
{runtimeConfig.enableSQLiteProvider && environment.isDesktop ? (
|
||||
<StyledImportWorkspaceCardPill>
|
||||
<MenuItem
|
||||
onClick={onAddWorkspace}
|
||||
data-testid="add-workspace"
|
||||
style={{
|
||||
height: 'auto',
|
||||
padding: '8px 12px',
|
||||
}}
|
||||
>
|
||||
<StyledCreateWorkspaceCardPillContent>
|
||||
<StyledCreateWorkspaceCardPillIcon>
|
||||
<ImportIcon />
|
||||
</StyledCreateWorkspaceCardPillIcon>
|
||||
<div>
|
||||
<p>{t['com.affine.workspace.local.import']()}</p>
|
||||
</div>
|
||||
</StyledCreateWorkspaceCardPillContent>
|
||||
</MenuItem>
|
||||
</StyledImportWorkspaceCardPill>
|
||||
) : null}
|
||||
<StyledCreateWorkspaceCardPill>
|
||||
<MenuItem
|
||||
style={{
|
||||
height: 'auto',
|
||||
padding: '8px 12px',
|
||||
}}
|
||||
onClick={onNewWorkspace}
|
||||
data-testid="new-workspace"
|
||||
>
|
||||
<StyledCreateWorkspaceCardPillContent>
|
||||
<StyledCreateWorkspaceCardPillIcon>
|
||||
<PlusIcon />
|
||||
</StyledCreateWorkspaceCardPillIcon>
|
||||
<div>
|
||||
<p>{t['New Workspace']()}</p>
|
||||
</div>
|
||||
</StyledCreateWorkspaceCardPillContent>
|
||||
</MenuItem>
|
||||
</StyledCreateWorkspaceCardPill>
|
||||
</StyledModalContent>
|
||||
</ScrollableContainer>
|
||||
<Footer />
|
||||
</ModalWrapper>
|
||||
</Modal>
|
||||
</StyledModalBody>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -81,11 +81,33 @@ export const StyledCreateWorkspaceCardPillContainer = styled('div')(() => {
|
||||
});
|
||||
|
||||
export const StyledCreateWorkspaceCardPill = styled('div')(() => {
|
||||
return {
|
||||
borderRadius: '8px',
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
height: '58px',
|
||||
background: 'var(--affine-background-primary-color)',
|
||||
border: `1px solid var(--affine-border-color)`,
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledSignInCardPill = styled('div')(() => {
|
||||
return {
|
||||
borderRadius: '8px',
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
height: '58px',
|
||||
marginBottom: '6px',
|
||||
background: 'var(--affine-background-primary-color)',
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledImportWorkspaceCardPill = styled('div')(() => {
|
||||
return {
|
||||
borderRadius: '5px',
|
||||
display: 'flex',
|
||||
boxShadow: '0px 0px 6px 0px rgba(0, 0, 0, 0.1)',
|
||||
background: 'var(--affine-background-primary-color)',
|
||||
width: '100%',
|
||||
marginBottom: '12px',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -94,7 +116,6 @@ export const StyledCreateWorkspaceCardPillContent = styled('div')(() => {
|
||||
display: 'flex',
|
||||
gap: '12px',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -106,13 +127,30 @@ export const StyledCreateWorkspaceCardPillIcon = styled('div')(() => {
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledCreateWorkspaceCardPillTextSecondary = styled('div')(() => {
|
||||
export const StyledSignInCardPillTextCotainer = styled('div')(() => {
|
||||
return {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledSignInCardPillTextSecondary = styled('div')(() => {
|
||||
return {
|
||||
fontSize: '12px',
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledSignInCardPillTextPrimary = styled('div')(() => {
|
||||
return {
|
||||
fontSize: 'var(--affine-font-base)',
|
||||
fontWeight: 600,
|
||||
lineHeight: '24px',
|
||||
maxWidth: '200px',
|
||||
...textEllipsis(1),
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledModalHeaderLeft = styled('div')(() => {
|
||||
return { ...displayFlex('flex-start', 'center') };
|
||||
});
|
||||
@@ -120,6 +158,7 @@ export const StyledModalTitle = styled('div')(() => {
|
||||
return {
|
||||
fontWeight: 600,
|
||||
fontSize: 'var(--affine-font-h6)',
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -134,10 +173,9 @@ export const StyledHelperContainer = styled('div')(() => {
|
||||
});
|
||||
|
||||
export const StyledModalContent = styled('div')({
|
||||
height: '540px',
|
||||
padding: '8px 40px',
|
||||
...displayFlex('space-between', 'flex-start', 'flex-start'),
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'column',
|
||||
});
|
||||
export const StyledOperationWrapper = styled('div')(() => {
|
||||
return {
|
||||
@@ -162,11 +200,22 @@ export const StyleWorkspaceAdd = styled('div')(() => {
|
||||
export const StyledModalHeader = styled('div')(() => {
|
||||
return {
|
||||
width: '100%',
|
||||
marginTop: '10px',
|
||||
left: 0,
|
||||
top: 0,
|
||||
borderRadius: '24px 24px 0 0',
|
||||
padding: '10px 40px',
|
||||
padding: '12px 14px',
|
||||
...displayFlex('space-between', 'center'),
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledModalBody = styled('div')(() => {
|
||||
return {
|
||||
borderRadius: '8px',
|
||||
padding: '12px',
|
||||
display: 'inline-flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
gap: '12px',
|
||||
background: 'var(--affine-white)',
|
||||
};
|
||||
});
|
||||
|
||||
+2
@@ -32,6 +32,7 @@ export const WorkspaceSelector = ({
|
||||
|
||||
// Open dialog when `Enter` or `Space` pressed
|
||||
// TODO-Doma Refactor with `@radix-ui/react-dialog` or other libraries that handle these out of the box and be accessible by default
|
||||
// TODO: Delete this?
|
||||
const handleKeyDown = useCallback(
|
||||
(e: React.KeyboardEvent) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
@@ -50,6 +51,7 @@ export const WorkspaceSelector = ({
|
||||
onClick={onClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
data-testid="current-workspace"
|
||||
id="current-workspace"
|
||||
>
|
||||
<WorkspaceAvatar
|
||||
data-testid="workspace-avatar"
|
||||
|
||||
@@ -126,6 +126,7 @@ export const AllWorkspaceModals = (): ReactElement => {
|
||||
);
|
||||
const setCurrentPageId = useSetAtom(currentPageIdAtom);
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const [, startCloseTransition] = useTransition();
|
||||
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
|
||||
|
||||
const handleOpenSettingModal = useCallback(
|
||||
@@ -153,7 +154,9 @@ export const AllWorkspaceModals = (): ReactElement => {
|
||||
isOpenCreateWorkspaceModal === false
|
||||
}
|
||||
onClose={useCallback(() => {
|
||||
setOpenWorkspacesModal(false);
|
||||
startCloseTransition(() => {
|
||||
setOpenWorkspacesModal(false);
|
||||
});
|
||||
}, [setOpenWorkspacesModal])}
|
||||
onMoveWorkspace={useCallback(
|
||||
(activeId, overId) => {
|
||||
@@ -169,10 +172,12 @@ export const AllWorkspaceModals = (): ReactElement => {
|
||||
)}
|
||||
onClickWorkspace={useCallback(
|
||||
workspaceId => {
|
||||
setOpenWorkspacesModal(false);
|
||||
setCurrentWorkspaceId(workspaceId);
|
||||
setCurrentPageId(null);
|
||||
jumpToSubPath(workspaceId, WorkspaceSubPath.ALL);
|
||||
startCloseTransition(() => {
|
||||
setOpenWorkspacesModal(false);
|
||||
setCurrentWorkspaceId(workspaceId);
|
||||
setCurrentPageId(null);
|
||||
jumpToSubPath(workspaceId, WorkspaceSubPath.ALL);
|
||||
});
|
||||
},
|
||||
[
|
||||
jumpToSubPath,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { pluginRegisterPromise } from '@affine/core/bootstrap/register-plugins';
|
||||
import { routes } from '@affine/core/router';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { StoryContext, StoryFn } from '@storybook/react';
|
||||
import type { Decorator, StoryFn } from '@storybook/react';
|
||||
import { userEvent, waitFor } from '@storybook/testing-library';
|
||||
import { use } from 'foxact/use';
|
||||
import { Outlet, useLocation } from 'react-router-dom';
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
withRouter,
|
||||
} from 'storybook-addon-react-router-v6';
|
||||
|
||||
const withCleanLocalStorage = (Story: StoryFn, context: StoryContext) => {
|
||||
const withCleanLocalStorage: Decorator = (Story, context) => {
|
||||
localStorage.clear();
|
||||
return <Story {...context.args} />;
|
||||
return <Story {...context} />;
|
||||
};
|
||||
|
||||
const FakeApp = () => {
|
||||
@@ -78,3 +78,33 @@ NotFoundPage.parameters = {
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export const WorkspaceList: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
WorkspaceList.play = async ({ canvasElement }) => {
|
||||
// click current-workspace
|
||||
await waitFor(
|
||||
() => {
|
||||
assertExists(
|
||||
canvasElement.querySelector('[data-testid="current-workspace"]')
|
||||
);
|
||||
},
|
||||
{
|
||||
timeout: 5000,
|
||||
}
|
||||
);
|
||||
const currentWorkspace = canvasElement.querySelector(
|
||||
'[data-testid="current-workspace"]'
|
||||
) as Element;
|
||||
await userEvent.click(currentWorkspace);
|
||||
};
|
||||
WorkspaceList.decorators = [withRouter, withCleanLocalStorage];
|
||||
WorkspaceList.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(routes),
|
||||
location: {
|
||||
path: '/',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@ import { SettingsIcon } from '@blocksuite/icons';
|
||||
import {
|
||||
CloudWorkspaceIcon as DefaultCloudWorkspaceIcon,
|
||||
CollaborationIcon as DefaultJoinedWorkspaceIcon,
|
||||
LocalDataIcon as DefaultLocalDataIcon,
|
||||
LocalWorkspaceIcon as DefaultLocalWorkspaceIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||
@@ -16,8 +15,8 @@ import { WorkspaceAvatar } from '../../workspace-avatar';
|
||||
import {
|
||||
StyledCard,
|
||||
StyledSettingLink,
|
||||
StyleWorkspaceInfo,
|
||||
StyleWorkspaceTitle,
|
||||
StyledWorkspaceInfo,
|
||||
StyledWorkspaceTitle,
|
||||
} from './styles';
|
||||
|
||||
const JoinedWorkspaceIcon = () => {
|
||||
@@ -31,9 +30,9 @@ const CloudWorkspaceIcon = () => {
|
||||
return <DefaultCloudWorkspaceIcon style={{ color: '#60A5FA' }} />;
|
||||
};
|
||||
|
||||
const LocalDataIcon = () => {
|
||||
return <DefaultLocalDataIcon style={{ color: '#62CD80' }} />;
|
||||
};
|
||||
// const LocalDataIcon = () => {
|
||||
// return <DefaultLocalDataIcon style={{ color: '#62CD80' }} />;
|
||||
// };
|
||||
|
||||
export interface WorkspaceTypeProps {
|
||||
flavour: WorkspaceFlavour;
|
||||
@@ -46,7 +45,7 @@ const WorkspaceType = ({ flavour }: WorkspaceTypeProps) => {
|
||||
|
||||
if (flavour === WorkspaceFlavour.LOCAL) {
|
||||
return (
|
||||
<p title={t['Local Workspace']()}>
|
||||
<p style={{ fontSize: '10px' }} title={t['Local Workspace']()}>
|
||||
<LocalWorkspaceIcon />
|
||||
<span>{t['Local Workspace']()}</span>
|
||||
</p>
|
||||
@@ -54,12 +53,12 @@ const WorkspaceType = ({ flavour }: WorkspaceTypeProps) => {
|
||||
}
|
||||
|
||||
return isOwner ? (
|
||||
<p title={t['Cloud Workspace']()}>
|
||||
<p style={{ fontSize: '10px' }} title={t['Cloud Workspace']()}>
|
||||
<CloudWorkspaceIcon />
|
||||
<span>{t['Cloud Workspace']()}</span>
|
||||
</p>
|
||||
) : (
|
||||
<p title={t['Joined Workspace']()}>
|
||||
<p style={{ fontSize: '10px' }} title={t['Joined Workspace']()}>
|
||||
<JoinedWorkspaceIcon />
|
||||
<span>{t['Joined Workspace']()}</span>
|
||||
</p>
|
||||
@@ -79,7 +78,7 @@ export const WorkspaceCard = ({
|
||||
currentWorkspaceId,
|
||||
meta,
|
||||
}: WorkspaceCardProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
// const t = useAFFiNEI18N();
|
||||
const workspace = useStaticBlockSuiteWorkspace(meta.id);
|
||||
const [name] = useBlockSuiteWorkspaceName(workspace);
|
||||
|
||||
@@ -91,18 +90,18 @@ export const WorkspaceCard = ({
|
||||
}, [onClick, meta.id])}
|
||||
active={workspace.id === currentWorkspaceId}
|
||||
>
|
||||
<WorkspaceAvatar size={58} workspace={workspace} />
|
||||
<WorkspaceAvatar size={28} workspace={workspace} />
|
||||
|
||||
<StyleWorkspaceInfo>
|
||||
<StyleWorkspaceTitle>{name}</StyleWorkspaceTitle>
|
||||
<StyledWorkspaceInfo>
|
||||
<StyledWorkspaceTitle>{name}</StyledWorkspaceTitle>
|
||||
<WorkspaceType flavour={meta.flavour} />
|
||||
{meta.flavour === WorkspaceFlavour.LOCAL && (
|
||||
{/* {meta.flavour === WorkspaceFlavour.LOCAL && (
|
||||
<p title={t['Available Offline']()}>
|
||||
<LocalDataIcon />
|
||||
<span>{t['Available Offline']()}</span>
|
||||
</p>
|
||||
)}
|
||||
</StyleWorkspaceInfo>
|
||||
)} */}
|
||||
</StyledWorkspaceInfo>
|
||||
<StyledSettingLink
|
||||
className="setting-entry"
|
||||
onClick={e => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { IconButton } from '@toeverything/components/button';
|
||||
|
||||
import { displayFlex, styled, textEllipsis } from '../../../styles';
|
||||
|
||||
export const StyleWorkspaceInfo = styled('div')(() => {
|
||||
export const StyledWorkspaceInfo = styled('div')(() => {
|
||||
return {
|
||||
marginLeft: '15px',
|
||||
width: '202px',
|
||||
@@ -23,13 +23,13 @@ export const StyleWorkspaceInfo = styled('div')(() => {
|
||||
};
|
||||
});
|
||||
|
||||
export const StyleWorkspaceTitle = styled('div')(() => {
|
||||
export const StyledWorkspaceTitle = styled('div')(() => {
|
||||
return {
|
||||
fontSize: 'var(--affine-font-base)',
|
||||
fontWeight: 600,
|
||||
lineHeight: '24px',
|
||||
marginBottom: '10px',
|
||||
maxWidth: '200px',
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
...textEllipsis(1),
|
||||
};
|
||||
});
|
||||
@@ -38,19 +38,21 @@ export const StyledCard = styled('div')<{
|
||||
active?: boolean;
|
||||
}>(({ active }) => {
|
||||
const borderColor = active ? 'var(--affine-primary-color)' : 'transparent';
|
||||
const backgroundColor = active ? 'var(--affine-white)' : 'transparent';
|
||||
return {
|
||||
width: '310px',
|
||||
height: '124px',
|
||||
width: '280px',
|
||||
height: '58px',
|
||||
cursor: 'pointer',
|
||||
padding: '16px',
|
||||
boxShadow: 'var(--affine-shadow-1)',
|
||||
borderRadius: '12px',
|
||||
border: `1px solid ${borderColor}`,
|
||||
...displayFlex('flex-start', 'flex-start'),
|
||||
marginBottom: '24px',
|
||||
marginBottom: '12px',
|
||||
transition: 'background .2s',
|
||||
background: 'var(--affine-white-80)',
|
||||
alignItems: 'center',
|
||||
position: 'relative',
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
background: backgroundColor,
|
||||
':hover': {
|
||||
background: 'var(--affine-hover-color)',
|
||||
'.add-icon': {
|
||||
@@ -96,3 +98,9 @@ export const StyledSettingLink = styled(IconButton)(() => {
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledWorkspaceType = styled('p')(() => {
|
||||
return {
|
||||
fontSize: 10,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -470,6 +470,12 @@
|
||||
"com.affine.auth.create.count": "Create Account",
|
||||
"com.affine.expired.page.title": "This link has expired...",
|
||||
"com.affine.expired.page.subtitle": "Please request a new reset password link.",
|
||||
"com.affine.workspace.cloud.join": "Join Workspace",
|
||||
"com.affine.workspace.cloud.account.settings": "Account Settings",
|
||||
"com.affine.workspace.cloud.account.logout": "Log Out",
|
||||
"com.affine.workspace.cloud.sync": "Cloud sync",
|
||||
"com.affine.workspace.cloud.auth": "Sign up/ Sign in",
|
||||
"com.affine.workspace.local.import": "Import Workspace",
|
||||
"core": "core",
|
||||
"dark": "Dark",
|
||||
"emptyAllPages": "Click on the <1>$t(New Page)</1> button to create your first page.",
|
||||
|
||||
@@ -625,7 +625,7 @@ test('tooltips for all buttons should be visible when hovering', async ({
|
||||
}
|
||||
|
||||
await locator.getByTestId('download-button').hover();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.waitForTimeout(1000);
|
||||
{
|
||||
const element = await page.getByRole('tooltip');
|
||||
const downloadTooltip = await element.getByText('Download').count();
|
||||
|
||||
@@ -45,8 +45,7 @@ test('create one workspace in the workspace list', async ({
|
||||
expect(workspaceCards.length).toBe(2);
|
||||
|
||||
//check page list length
|
||||
const closeWorkspaceModal = page.getByTestId('close-workspace-modal');
|
||||
await closeWorkspaceModal.click();
|
||||
await page.keyboard.press('Escape');
|
||||
await clickSideBarAllPageButton(page);
|
||||
await page.waitForTimeout(1000);
|
||||
const pageList = page.locator('[data-testid=page-list-item]');
|
||||
@@ -91,6 +90,7 @@ test('create multi workspace in the workspace list', async ({
|
||||
expect(currentWorkspace.flavour).toContain('local');
|
||||
|
||||
await openWorkspaceListModal(page);
|
||||
await page.waitForTimeout(1000);
|
||||
const sourceElement = page.getByTestId('draggable-item').nth(2);
|
||||
const targetElement = page.getByTestId('draggable-item').nth(1);
|
||||
|
||||
|
||||
@@ -16,12 +16,14 @@ export async function createWorkspace(
|
||||
await openWorkspaceListModal(page);
|
||||
|
||||
// open create workspace modal
|
||||
await page.locator('.add-icon').click();
|
||||
await page.getByTestId('new-workspace').click();
|
||||
|
||||
// input workspace name
|
||||
await page.getByPlaceholder('Set a Workspace name').click();
|
||||
await page.getByPlaceholder('Set a Workspace name').fill(params.name);
|
||||
|
||||
// click create button
|
||||
return page.getByRole('button', { name: 'Create' }).click();
|
||||
return page.getByRole('button', { name: 'Create' }).click({
|
||||
delay: 500,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user