feat: new workspace switch dropdown design (#3700)

Co-authored-by: Alex Yang <himself65@outlook.com>
This commit is contained in:
danielchim
2023-08-16 17:18:43 -05:00
committed by GitHub
co-authored by Alex Yang
parent f369ca39f7
commit 9ab9c0c70d
11 changed files with 368 additions and 192 deletions
@@ -1,11 +1,4 @@
import { import { Menu, MenuItem, Tooltip } from '@affine/component';
Menu,
MenuItem,
Modal,
ModalCloseButton,
ModalWrapper,
Tooltip,
} from '@affine/component';
import { ScrollableContainer } from '@affine/component'; import { ScrollableContainer } from '@affine/component';
import { WorkspaceList } from '@affine/component/workspace-list'; import { WorkspaceList } from '@affine/component/workspace-list';
import type { import type {
@@ -15,28 +8,38 @@ import type {
import { WorkspaceFlavour } from '@affine/env/workspace'; import { WorkspaceFlavour } from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import type { RootWorkspaceMetadata } from '@affine/workspace/atom'; 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 { 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, StyledCreateWorkspaceCardPill,
StyledCreateWorkspaceCardPillContainer,
StyledCreateWorkspaceCardPillContent, StyledCreateWorkspaceCardPillContent,
StyledCreateWorkspaceCardPillIcon, StyledCreateWorkspaceCardPillIcon,
StyledCreateWorkspaceCardPillTextSecondary,
StyledHelperContainer, StyledHelperContainer,
StyledImportWorkspaceCardPill,
StyledModalBody,
StyledModalContent, StyledModalContent,
StyledModalHeader, StyledModalHeader,
StyledModalHeaderLeft, StyledModalHeaderLeft,
StyledModalTitle, StyledModalTitle,
StyledOperationWrapper, StyledOperationWrapper,
StyleWorkspaceAdd, StyledSignInCardPill,
StyleWorkspaceInfo, StyledSignInCardPillTextCotainer,
StyleWorkspaceTitle, StyledSignInCardPillTextPrimary,
StyledSignInCardPillTextSecondary,
} from './styles'; } from './styles';
interface WorkspaceModalProps { interface WorkspaceModalProps {
@@ -52,105 +55,94 @@ interface WorkspaceModalProps {
onMoveWorkspace: (activeId: string, overId: string) => void; onMoveWorkspace: (activeId: string, overId: string) => void;
} }
const CreateWorkspaceCard = ({ const AccountMenu = () => {
onNewWorkspace,
onAddWorkspace,
}: {
onNewWorkspace: () => void;
onAddWorkspace: () => void;
}) => {
const t = useAFFiNEI18N(); 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) { const CloudWorkSpaceList = ({
return ( disabled,
<Menu workspaces,
placement="auto" onClickWorkspace,
trigger={['click']} onClickWorkspaceSetting,
zIndex={1000} currentWorkspaceId,
content={ onMoveWorkspace,
<StyledCreateWorkspaceCardPillContainer> }: WorkspaceModalProps) => {
<StyledCreateWorkspaceCardPill> const t = useAFFiNEI18N();
<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>
<StyleWorkspaceInfo> return (
<StyleWorkspaceTitle>{t['New Workspace']()}</StyleWorkspaceTitle> <>
<p>{t['Create Or Import']()}</p> <StyledModalHeader>
</StyleWorkspaceInfo> <StyledModalHeaderLeft>
</StyledCreateWorkspaceCard> <StyledModalTitle>
</Menu> {t['com.affine.workspace.cloud.sync']()}
); </StyledModalTitle>
} else { <Tooltip
return ( content={t['Workspace description']()}
<div> placement="top-start"
<StyledCreateWorkspaceCard disablePortal={true}
onClick={onNewWorkspace} >
data-testid="new-workspace" <StyledHelperContainer>
> <HelpIcon />
<StyleWorkspaceAdd className="add-icon"> </StyledHelperContainer>
<PlusIcon /> </Tooltip>
</StyleWorkspaceAdd> </StyledModalHeaderLeft>
<StyleWorkspaceInfo> <StyledOperationWrapper>
<StyleWorkspaceTitle>{t['New Workspace']()}</StyleWorkspaceTitle> <Menu
<p>{t['Create Or Import']()}</p> placement="bottom-end"
</StyleWorkspaceInfo> trigger={['click']}
</StyledCreateWorkspaceCard> content={<AccountMenu />}
</div> 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 = ({ export const WorkspaceListModal = ({
@@ -166,19 +158,77 @@ export const WorkspaceListModal = ({
onMoveWorkspace, onMoveWorkspace,
}: WorkspaceModalProps) => { }: WorkspaceModalProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const setOpen = useSetAtom(openDisableCloudAlertModalAtom);
// TODO: AFFiNE Cloud support
const isLoggedIn = false;
const anchorEl = document.getElementById('current-workspace');
return ( return (
<Modal open={open} onClose={onClose}> <Popover
<ModalWrapper sx={{
width={720} color: 'success.main',
height={690} zIndex: 999,
style={{ '& .MuiPopover-paper': {
display: 'flex', borderRadius: '8px',
flexDirection: 'column', boxShadow: 'var(--affine-shadow-1)',
}} },
> }}
<StyledModalHeader> open={open}
<StyledModalHeaderLeft> anchorEl={anchorEl}
<StyledModalTitle>{t['My Workspaces']()}</StyledModalTitle> 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 <Tooltip
content={t['Workspace description']()} content={t['Workspace description']()}
placement="top-start" placement="top-start"
@@ -188,19 +238,7 @@ export const WorkspaceListModal = ({
<HelpIcon /> <HelpIcon />
</StyledHelperContainer> </StyledHelperContainer>
</Tooltip> </Tooltip>
</StyledModalHeaderLeft> </StyledModalHeader>
<StyledOperationWrapper>
<ModalCloseButton
data-testid="close-workspace-modal"
onClick={() => {
onClose();
}}
absolute={false}
/>
</StyledOperationWrapper>
</StyledModalHeader>
<ScrollableContainer>
<StyledModalContent> <StyledModalContent>
<WorkspaceList <WorkspaceList
disabled={disabled} disabled={disabled}
@@ -222,14 +260,51 @@ export const WorkspaceListModal = ({
[onMoveWorkspace] [onMoveWorkspace]
)} )}
/> />
<CreateWorkspaceCard </StyledModalContent>
onNewWorkspace={onNewWorkspace} <StyledModalContent>
onAddWorkspace={onAddWorkspace} {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> </StyledModalContent>
</ScrollableContainer> </ScrollableContainer>
<Footer /> </StyledModalBody>
</ModalWrapper> </Popover>
</Modal>
); );
}; };
@@ -81,11 +81,33 @@ export const StyledCreateWorkspaceCardPillContainer = styled('div')(() => {
}); });
export const StyledCreateWorkspaceCardPill = 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 { return {
borderRadius: '5px', borderRadius: '5px',
display: 'flex', display: 'flex',
boxShadow: '0px 0px 6px 0px rgba(0, 0, 0, 0.1)', width: '100%',
background: 'var(--affine-background-primary-color)', marginBottom: '12px',
}; };
}); });
@@ -94,7 +116,6 @@ export const StyledCreateWorkspaceCardPillContent = styled('div')(() => {
display: 'flex', display: 'flex',
gap: '12px', gap: '12px',
alignItems: 'center', 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 { return {
fontSize: '12px', fontSize: '12px',
color: 'var(--affine-text-secondary-color)', 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')(() => { export const StyledModalHeaderLeft = styled('div')(() => {
return { ...displayFlex('flex-start', 'center') }; return { ...displayFlex('flex-start', 'center') };
}); });
@@ -120,6 +158,7 @@ export const StyledModalTitle = styled('div')(() => {
return { return {
fontWeight: 600, fontWeight: 600,
fontSize: 'var(--affine-font-h6)', 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')({ export const StyledModalContent = styled('div')({
height: '540px',
padding: '8px 40px',
...displayFlex('space-between', 'flex-start', 'flex-start'), ...displayFlex('space-between', 'flex-start', 'flex-start'),
flexWrap: 'wrap', flexWrap: 'wrap',
flexDirection: 'column',
}); });
export const StyledOperationWrapper = styled('div')(() => { export const StyledOperationWrapper = styled('div')(() => {
return { return {
@@ -162,11 +200,22 @@ export const StyleWorkspaceAdd = styled('div')(() => {
export const StyledModalHeader = styled('div')(() => { export const StyledModalHeader = styled('div')(() => {
return { return {
width: '100%', width: '100%',
marginTop: '10px',
left: 0, left: 0,
top: 0, top: 0,
borderRadius: '24px 24px 0 0', borderRadius: '24px 24px 0 0',
padding: '10px 40px', padding: '12px 14px',
...displayFlex('space-between', 'center'), ...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)',
};
});
@@ -32,6 +32,7 @@ export const WorkspaceSelector = ({
// Open dialog when `Enter` or `Space` pressed // 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-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( const handleKeyDown = useCallback(
(e: React.KeyboardEvent) => { (e: React.KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') { if (e.key === 'Enter' || e.key === ' ') {
@@ -50,6 +51,7 @@ export const WorkspaceSelector = ({
onClick={onClick} onClick={onClick}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
data-testid="current-workspace" data-testid="current-workspace"
id="current-workspace"
> >
<WorkspaceAvatar <WorkspaceAvatar
data-testid="workspace-avatar" data-testid="workspace-avatar"
+10 -5
View File
@@ -126,6 +126,7 @@ export const AllWorkspaceModals = (): ReactElement => {
); );
const setCurrentPageId = useSetAtom(currentPageIdAtom); const setCurrentPageId = useSetAtom(currentPageIdAtom);
const [isPending, startTransition] = useTransition(); const [isPending, startTransition] = useTransition();
const [, startCloseTransition] = useTransition();
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom); const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
const handleOpenSettingModal = useCallback( const handleOpenSettingModal = useCallback(
@@ -153,7 +154,9 @@ export const AllWorkspaceModals = (): ReactElement => {
isOpenCreateWorkspaceModal === false isOpenCreateWorkspaceModal === false
} }
onClose={useCallback(() => { onClose={useCallback(() => {
setOpenWorkspacesModal(false); startCloseTransition(() => {
setOpenWorkspacesModal(false);
});
}, [setOpenWorkspacesModal])} }, [setOpenWorkspacesModal])}
onMoveWorkspace={useCallback( onMoveWorkspace={useCallback(
(activeId, overId) => { (activeId, overId) => {
@@ -169,10 +172,12 @@ export const AllWorkspaceModals = (): ReactElement => {
)} )}
onClickWorkspace={useCallback( onClickWorkspace={useCallback(
workspaceId => { workspaceId => {
setOpenWorkspacesModal(false); startCloseTransition(() => {
setCurrentWorkspaceId(workspaceId); setOpenWorkspacesModal(false);
setCurrentPageId(null); setCurrentWorkspaceId(workspaceId);
jumpToSubPath(workspaceId, WorkspaceSubPath.ALL); setCurrentPageId(null);
jumpToSubPath(workspaceId, WorkspaceSubPath.ALL);
});
}, },
[ [
jumpToSubPath, jumpToSubPath,
+33 -3
View File
@@ -1,7 +1,7 @@
import { pluginRegisterPromise } from '@affine/core/bootstrap/register-plugins'; import { pluginRegisterPromise } from '@affine/core/bootstrap/register-plugins';
import { routes } from '@affine/core/router'; import { routes } from '@affine/core/router';
import { assertExists } from '@blocksuite/global/utils'; 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 { userEvent, waitFor } from '@storybook/testing-library';
import { use } from 'foxact/use'; import { use } from 'foxact/use';
import { Outlet, useLocation } from 'react-router-dom'; import { Outlet, useLocation } from 'react-router-dom';
@@ -11,9 +11,9 @@ import {
withRouter, withRouter,
} from 'storybook-addon-react-router-v6'; } from 'storybook-addon-react-router-v6';
const withCleanLocalStorage = (Story: StoryFn, context: StoryContext) => { const withCleanLocalStorage: Decorator = (Story, context) => {
localStorage.clear(); localStorage.clear();
return <Story {...context.args} />; return <Story {...context} />;
}; };
const FakeApp = () => { 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 { import {
CloudWorkspaceIcon as DefaultCloudWorkspaceIcon, CloudWorkspaceIcon as DefaultCloudWorkspaceIcon,
CollaborationIcon as DefaultJoinedWorkspaceIcon, CollaborationIcon as DefaultJoinedWorkspaceIcon,
LocalDataIcon as DefaultLocalDataIcon,
LocalWorkspaceIcon as DefaultLocalWorkspaceIcon, LocalWorkspaceIcon as DefaultLocalWorkspaceIcon,
} from '@blocksuite/icons'; } from '@blocksuite/icons';
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
@@ -16,8 +15,8 @@ import { WorkspaceAvatar } from '../../workspace-avatar';
import { import {
StyledCard, StyledCard,
StyledSettingLink, StyledSettingLink,
StyleWorkspaceInfo, StyledWorkspaceInfo,
StyleWorkspaceTitle, StyledWorkspaceTitle,
} from './styles'; } from './styles';
const JoinedWorkspaceIcon = () => { const JoinedWorkspaceIcon = () => {
@@ -31,9 +30,9 @@ const CloudWorkspaceIcon = () => {
return <DefaultCloudWorkspaceIcon style={{ color: '#60A5FA' }} />; return <DefaultCloudWorkspaceIcon style={{ color: '#60A5FA' }} />;
}; };
const LocalDataIcon = () => { // const LocalDataIcon = () => {
return <DefaultLocalDataIcon style={{ color: '#62CD80' }} />; // return <DefaultLocalDataIcon style={{ color: '#62CD80' }} />;
}; // };
export interface WorkspaceTypeProps { export interface WorkspaceTypeProps {
flavour: WorkspaceFlavour; flavour: WorkspaceFlavour;
@@ -46,7 +45,7 @@ const WorkspaceType = ({ flavour }: WorkspaceTypeProps) => {
if (flavour === WorkspaceFlavour.LOCAL) { if (flavour === WorkspaceFlavour.LOCAL) {
return ( return (
<p title={t['Local Workspace']()}> <p style={{ fontSize: '10px' }} title={t['Local Workspace']()}>
<LocalWorkspaceIcon /> <LocalWorkspaceIcon />
<span>{t['Local Workspace']()}</span> <span>{t['Local Workspace']()}</span>
</p> </p>
@@ -54,12 +53,12 @@ const WorkspaceType = ({ flavour }: WorkspaceTypeProps) => {
} }
return isOwner ? ( return isOwner ? (
<p title={t['Cloud Workspace']()}> <p style={{ fontSize: '10px' }} title={t['Cloud Workspace']()}>
<CloudWorkspaceIcon /> <CloudWorkspaceIcon />
<span>{t['Cloud Workspace']()}</span> <span>{t['Cloud Workspace']()}</span>
</p> </p>
) : ( ) : (
<p title={t['Joined Workspace']()}> <p style={{ fontSize: '10px' }} title={t['Joined Workspace']()}>
<JoinedWorkspaceIcon /> <JoinedWorkspaceIcon />
<span>{t['Joined Workspace']()}</span> <span>{t['Joined Workspace']()}</span>
</p> </p>
@@ -79,7 +78,7 @@ export const WorkspaceCard = ({
currentWorkspaceId, currentWorkspaceId,
meta, meta,
}: WorkspaceCardProps) => { }: WorkspaceCardProps) => {
const t = useAFFiNEI18N(); // const t = useAFFiNEI18N();
const workspace = useStaticBlockSuiteWorkspace(meta.id); const workspace = useStaticBlockSuiteWorkspace(meta.id);
const [name] = useBlockSuiteWorkspaceName(workspace); const [name] = useBlockSuiteWorkspaceName(workspace);
@@ -91,18 +90,18 @@ export const WorkspaceCard = ({
}, [onClick, meta.id])} }, [onClick, meta.id])}
active={workspace.id === currentWorkspaceId} active={workspace.id === currentWorkspaceId}
> >
<WorkspaceAvatar size={58} workspace={workspace} /> <WorkspaceAvatar size={28} workspace={workspace} />
<StyleWorkspaceInfo> <StyledWorkspaceInfo>
<StyleWorkspaceTitle>{name}</StyleWorkspaceTitle> <StyledWorkspaceTitle>{name}</StyledWorkspaceTitle>
<WorkspaceType flavour={meta.flavour} /> <WorkspaceType flavour={meta.flavour} />
{meta.flavour === WorkspaceFlavour.LOCAL && ( {/* {meta.flavour === WorkspaceFlavour.LOCAL && (
<p title={t['Available Offline']()}> <p title={t['Available Offline']()}>
<LocalDataIcon /> <LocalDataIcon />
<span>{t['Available Offline']()}</span> <span>{t['Available Offline']()}</span>
</p> </p>
)} )} */}
</StyleWorkspaceInfo> </StyledWorkspaceInfo>
<StyledSettingLink <StyledSettingLink
className="setting-entry" className="setting-entry"
onClick={e => { onClick={e => {
@@ -2,7 +2,7 @@ import { IconButton } from '@toeverything/components/button';
import { displayFlex, styled, textEllipsis } from '../../../styles'; import { displayFlex, styled, textEllipsis } from '../../../styles';
export const StyleWorkspaceInfo = styled('div')(() => { export const StyledWorkspaceInfo = styled('div')(() => {
return { return {
marginLeft: '15px', marginLeft: '15px',
width: '202px', width: '202px',
@@ -23,13 +23,13 @@ export const StyleWorkspaceInfo = styled('div')(() => {
}; };
}); });
export const StyleWorkspaceTitle = styled('div')(() => { export const StyledWorkspaceTitle = styled('div')(() => {
return { return {
fontSize: 'var(--affine-font-base)', fontSize: 'var(--affine-font-base)',
fontWeight: 600, fontWeight: 600,
lineHeight: '24px', lineHeight: '24px',
marginBottom: '10px',
maxWidth: '200px', maxWidth: '200px',
color: 'var(--affine-text-primary-color)',
...textEllipsis(1), ...textEllipsis(1),
}; };
}); });
@@ -38,19 +38,21 @@ export const StyledCard = styled('div')<{
active?: boolean; active?: boolean;
}>(({ active }) => { }>(({ active }) => {
const borderColor = active ? 'var(--affine-primary-color)' : 'transparent'; const borderColor = active ? 'var(--affine-primary-color)' : 'transparent';
const backgroundColor = active ? 'var(--affine-white)' : 'transparent';
return { return {
width: '310px', width: '280px',
height: '124px', height: '58px',
cursor: 'pointer', cursor: 'pointer',
padding: '16px', padding: '16px',
boxShadow: 'var(--affine-shadow-1)',
borderRadius: '12px', borderRadius: '12px',
border: `1px solid ${borderColor}`, border: `1px solid ${borderColor}`,
...displayFlex('flex-start', 'flex-start'), ...displayFlex('flex-start', 'flex-start'),
marginBottom: '24px', marginBottom: '12px',
transition: 'background .2s', transition: 'background .2s',
background: 'var(--affine-white-80)', alignItems: 'center',
position: 'relative', position: 'relative',
color: 'var(--affine-text-secondary-color)',
background: backgroundColor,
':hover': { ':hover': {
background: 'var(--affine-hover-color)', background: 'var(--affine-hover-color)',
'.add-icon': { '.add-icon': {
@@ -96,3 +98,9 @@ export const StyledSettingLink = styled(IconButton)(() => {
}, },
}; };
}); });
export const StyledWorkspaceType = styled('p')(() => {
return {
fontSize: 10,
};
});
+6
View File
@@ -470,6 +470,12 @@
"com.affine.auth.create.count": "Create Account", "com.affine.auth.create.count": "Create Account",
"com.affine.expired.page.title": "This link has expired...", "com.affine.expired.page.title": "This link has expired...",
"com.affine.expired.page.subtitle": "Please request a new reset password link.", "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", "core": "core",
"dark": "Dark", "dark": "Dark",
"emptyAllPages": "Click on the <1>$t(New Page)</1> button to create your first page.", "emptyAllPages": "Click on the <1>$t(New Page)</1> button to create your first page.",
+1 -1
View File
@@ -625,7 +625,7 @@ test('tooltips for all buttons should be visible when hovering', async ({
} }
await locator.getByTestId('download-button').hover(); await locator.getByTestId('download-button').hover();
await page.waitForTimeout(2000); await page.waitForTimeout(1000);
{ {
const element = await page.getByRole('tooltip'); const element = await page.getByRole('tooltip');
const downloadTooltip = await element.getByText('Download').count(); 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); expect(workspaceCards.length).toBe(2);
//check page list length //check page list length
const closeWorkspaceModal = page.getByTestId('close-workspace-modal'); await page.keyboard.press('Escape');
await closeWorkspaceModal.click();
await clickSideBarAllPageButton(page); await clickSideBarAllPageButton(page);
await page.waitForTimeout(1000); await page.waitForTimeout(1000);
const pageList = page.locator('[data-testid=page-list-item]'); 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'); expect(currentWorkspace.flavour).toContain('local');
await openWorkspaceListModal(page); await openWorkspaceListModal(page);
await page.waitForTimeout(1000);
const sourceElement = page.getByTestId('draggable-item').nth(2); const sourceElement = page.getByTestId('draggable-item').nth(2);
const targetElement = page.getByTestId('draggable-item').nth(1); const targetElement = page.getByTestId('draggable-item').nth(1);
+4 -2
View File
@@ -16,12 +16,14 @@ export async function createWorkspace(
await openWorkspaceListModal(page); await openWorkspaceListModal(page);
// open create workspace modal // open create workspace modal
await page.locator('.add-icon').click(); await page.getByTestId('new-workspace').click();
// input workspace name // input workspace name
await page.getByPlaceholder('Set a Workspace name').click(); await page.getByPlaceholder('Set a Workspace name').click();
await page.getByPlaceholder('Set a Workspace name').fill(params.name); await page.getByPlaceholder('Set a Workspace name').fill(params.name);
// click create button // click create button
return page.getByRole('button', { name: 'Create' }).click(); return page.getByRole('button', { name: 'Create' }).click({
delay: 500,
});
} }