fix(core): adjust share menu and upgrade-to-team page style (#10299)

close PD-2330 PD-2331 AF-2238
This commit is contained in:
JimmFly
2025-02-20 04:10:52 +00:00
parent b38abcb59c
commit 1d339c682b
14 changed files with 142 additions and 34 deletions

View File

@@ -100,6 +100,7 @@ export const errorHint = style({
export const contentStyle = style({ export const contentStyle = style({
paddingLeft: '0', paddingLeft: '0',
paddingRight: '0', paddingRight: '0',
overflowY: 'visible',
}); });
export const invitationLinkContent = style({ export const invitationLinkContent = style({

View File

@@ -8,6 +8,7 @@ import type {
WorkspaceProfileInfo, WorkspaceProfileInfo,
} from '@affine/core/modules/workspace'; } from '@affine/core/modules/workspace';
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant'; import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
import { useI18n } from '@affine/i18n';
import { import {
ArrowDownSmallIcon, ArrowDownSmallIcon,
CloudWorkspaceIcon, CloudWorkspaceIcon,
@@ -269,6 +270,7 @@ export const WorkspaceCard = forwardRef<
}, },
ref ref
) => { ) => {
const t = useI18n();
const information = useWorkspaceInfo(workspaceMetadata); const information = useWorkspaceInfo(workspaceMetadata);
const name = information?.name ?? UNTITLED_WORKSPACE_NAME; const name = information?.name ?? UNTITLED_WORKSPACE_NAME;
@@ -331,10 +333,18 @@ export const WorkspaceCard = forwardRef<
</Button> </Button>
) : null} ) : null}
{hideCollaborationIcon || information?.isOwner ? null : ( {hideCollaborationIcon || information?.isOwner ? null : (
<Tooltip
content={t['com.affine.settings.workspace.state.joined']()}
>
<CollaborationIcon className={styles.collaborationIcon} /> <CollaborationIcon className={styles.collaborationIcon} />
</Tooltip>
)} )}
{hideTeamWorkspaceIcon || !information?.isTeam ? null : ( {hideTeamWorkspaceIcon || !information?.isTeam ? null : (
<Tooltip
content={t['com.affine.settings.workspace.state.team']()}
>
<TeamWorkspaceIcon className={styles.collaborationIcon} /> <TeamWorkspaceIcon className={styles.collaborationIcon} />
</Tooltip>
)} )}
{onClickOpenSettings && ( {onClickOpenSettings && (
<div className={styles.settingButton} onClick={onOpenSettings}> <div className={styles.settingButton} onClick={onOpenSettings}>

View File

@@ -10,6 +10,7 @@ export const ConfirmAssignModal = ({
setOpen, setOpen,
member, member,
inputValue, inputValue,
placeholder,
setInputValue, setInputValue,
isEquals, isEquals,
onConfirm, onConfirm,
@@ -19,6 +20,7 @@ export const ConfirmAssignModal = ({
isEquals: boolean; isEquals: boolean;
member: Member; member: Member;
inputValue: string; inputValue: string;
placeholder?: string;
onConfirm: () => void; onConfirm: () => void;
setInputValue: (value: string) => void; setInputValue: (value: string) => void;
}) => { }) => {
@@ -35,31 +37,45 @@ export const ConfirmAssignModal = ({
confirmButtonOptions={{ disabled: !isEquals, variant: 'error' }} confirmButtonOptions={{ disabled: !isEquals, variant: 'error' }}
> >
<div className={styles.confirmAssignModalContent}> <div className={styles.confirmAssignModalContent}>
<div>
<p> <p>
{t['com.affine.payment.member.team.assign.confirm.description']({ {t['com.affine.payment.member.team.assign.confirm.description']({
name: member.name || member.email || member.id, name: member.name || member.email || member.id,
})} })}
</p> </p>
<p> <div className={styles.descriptions}>
{t['com.affine.payment.member.team.assign.confirm.description-1']()} <div className={styles.description}>
</p> <span className={styles.prefixDot} />
<p> <span>
{t['com.affine.payment.member.team.assign.confirm.description-2']()} {t[
</p> 'com.affine.payment.member.team.assign.confirm.description-1'
<p> ]()}
{t['com.affine.payment.member.team.assign.confirm.description-3']()} </span>
</p>
</div> </div>
<div className={styles.description}>
<span className={styles.prefixDot} />
<span>
{t[
'com.affine.payment.member.team.assign.confirm.description-2'
]()}
</span>
</div>
<div className={styles.description}>
<span className={styles.prefixDot} />
<span>
{t[
'com.affine.payment.member.team.assign.confirm.description-3'
]()}
</span>
</div>
</div>
<div className={styles.confirmInputContainer}> <div className={styles.confirmInputContainer}>
{t['com.affine.payment.member.team.assign.confirm.description-4']()} {t['com.affine.payment.member.team.assign.confirm.description-4']()}
<Input <Input
value={inputValue} value={inputValue}
inputStyle={{ fontSize: cssVar('fontSm') }} inputStyle={{ fontSize: cssVar('fontSm') }}
onChange={setInputValue} onChange={setInputValue}
placeholder={t.t( placeholder={placeholder}
'com.affine.payment.member.team.assign.confirm.placeholder'
)}
/> />
</div> </div>
</div> </div>

View File

@@ -247,6 +247,7 @@ const MemberItem = ({
setOpen={setOpen} setOpen={setOpen}
member={member} member={member}
inputValue={inputValue} inputValue={inputValue}
placeholder={workspaceName}
setInputValue={setInputValue} setInputValue={setInputValue}
isEquals={isEquals} isEquals={isEquals}
onConfirm={confirmAssign} onConfirm={confirmAssign}

View File

@@ -128,6 +128,25 @@ export const confirmAssignModalContent = style({
padding: '0', padding: '0',
}); });
export const descriptions = style({
display: 'flex',
flexDirection: 'column',
gap: '8px',
});
export const description = style({
display: 'flex',
});
export const prefixDot = style({
background: cssVarV2('icon/activated'),
width: '5px',
height: '5px',
borderRadius: '50%',
marginRight: '12px',
marginTop: '10px',
});
export const confirmInputContainer = style({ export const confirmInputContainer = style({
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',

View File

@@ -1,6 +1,8 @@
import { import {
Avatar,
Button, Button,
Divider, Divider,
IconButton,
Input, Input,
Menu, Menu,
MenuItem, MenuItem,
@@ -10,6 +12,7 @@ import {
Scrollable, Scrollable,
} from '@affine/component'; } from '@affine/component';
import { AuthPageContainer } from '@affine/component/auth-components'; import { AuthPageContainer } from '@affine/component/auth-components';
import { useSignOut } from '@affine/core/components/hooks/affine/use-sign-out';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info'; import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
import { PureWorkspaceCard } from '@affine/core/components/workspace-selector/workspace-card'; import { PureWorkspaceCard } from '@affine/core/components/workspace-selector/workspace-card';
@@ -22,7 +25,7 @@ import { buildShowcaseWorkspace } from '@affine/core/utils/first-app-data';
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant'; import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql'; import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
import { type I18nString, Trans, useI18n } from '@affine/i18n'; import { type I18nString, Trans, useI18n } from '@affine/i18n';
import { DoneIcon, NewPageIcon } from '@blocksuite/icons/rc'; import { DoneIcon, NewPageIcon, SignOutIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
@@ -54,11 +57,16 @@ export const Component = () => {
export const UpgradeToTeam = ({ recurring }: { recurring: string | null }) => { export const UpgradeToTeam = ({ recurring }: { recurring: string | null }) => {
const t = useI18n(); const t = useI18n();
const workspacesList = useService(WorkspacesService).list; const workspacesList = useService(WorkspacesService).list;
const workspaces = useLiveData(workspacesList.workspaces$); const workspaces = useLiveData(workspacesList.workspaces$);
const [openUpgrade, setOpenUpgrade] = useState(false); const [openUpgrade, setOpenUpgrade] = useState(false);
const [openCreate, setOpenCreate] = useState(false); const [openCreate, setOpenCreate] = useState(false);
const authService = useService(AuthService);
const user = useLiveData(authService.session.account$);
const onSignOut = useSignOut();
const [selectedWorkspace, setSelectedWorkspace] = const [selectedWorkspace, setSelectedWorkspace] =
useState<WorkspaceMetadata | null>(null); useState<WorkspaceMetadata | null>(null);
@@ -102,7 +110,6 @@ export const UpgradeToTeam = ({ recurring }: { recurring: string | null }) => {
> >
<MenuTrigger <MenuTrigger
className={styles.menuTrigger} className={styles.menuTrigger}
tooltip={menuTriggerText}
data-selected={!!selectedWorkspace} data-selected={!!selectedWorkspace}
> >
{menuTriggerText} {menuTriggerText}
@@ -144,6 +151,19 @@ export const UpgradeToTeam = ({ recurring }: { recurring: string | null }) => {
onSelect={setSelectedWorkspace} onSelect={setSelectedWorkspace}
/> />
</div> </div>
{user ? (
<div className={styles.userContainer}>
<Avatar url={user.avatar} name={user.label} />
<span className={styles.email}>{user.email}</span>
<IconButton
onClick={onSignOut}
size="20"
tooltip={t['404.signOut']()}
>
<SignOutIcon />
</IconButton>
</div>
) : null}
</div> </div>
</AuthPageContainer> </AuthPageContainer>
); );

View File

@@ -118,3 +118,14 @@ export const dialogFooter = style({
export const upgradeButtonInDialog = style({ export const upgradeButtonInDialog = style({
width: 'unset', width: 'unset',
}); });
export const userContainer = style({
display: 'flex',
alignItems: 'center',
marginTop: '28px',
});
export const email = style({
marginLeft: '4px',
marginRight: '8px',
});

View File

@@ -6,6 +6,7 @@ export const copyLinkContainerStyle = style({
alignItems: 'center', alignItems: 'center',
width: '100%', width: '100%',
position: 'relative', position: 'relative',
border: `1px solid ${cssVarV2('layer/insideBorder/blackBorder')}`,
selectors: { selectors: {
'&.secondary': { '&.secondary': {
padding: 0, padding: 0,

View File

@@ -97,8 +97,10 @@ export const MembersPermission = ({
</div> </div>
{disabled ? ( {disabled ? (
<div className={clsx(styles.menuTriggerStyle, 'disable')}> <div className={clsx(styles.menuTriggerStyle, 'disable')}>
<div className={styles.menuTriggerText}>
{showTips ? <Tips disable={disabled} /> : null} {currentRoleName} {showTips ? <Tips disable={disabled} /> : null} {currentRoleName}
</div> </div>
</div>
) : ( ) : (
<Menu <Menu
contentOptions={{ contentOptions={{
@@ -142,6 +144,7 @@ export const MembersPermission = ({
<MenuTrigger <MenuTrigger
className={styles.menuTriggerStyle} className={styles.menuTriggerStyle}
variant="plain" variant="plain"
suffixClassName={styles.suffixClassName}
contentStyle={{ contentStyle={{
width: '100%', width: '100%',
}} }}

View File

@@ -89,10 +89,12 @@ export const PublicDoc = ({ disabled }: { disabled?: boolean }) => {
</div> </div>
{disabled ? ( {disabled ? (
<div className={clsx(styles.menuTriggerStyle, 'disable')}> <div className={clsx(styles.menuTriggerStyle, 'disable')}>
<div className={styles.menuTriggerText}>
{isSharedPage {isSharedPage
? t['com.affine.share-menu.option.link.readonly']() ? t['com.affine.share-menu.option.link.readonly']()
: t['com.affine.share-menu.option.link.no-access']()} : t['com.affine.share-menu.option.link.no-access']()}
</div> </div>
</div>
) : ( ) : (
<Menu <Menu
contentOptions={{ contentOptions={{
@@ -128,6 +130,7 @@ export const PublicDoc = ({ disabled }: { disabled?: boolean }) => {
className={styles.menuTriggerStyle} className={styles.menuTriggerStyle}
data-testid="share-link-menu-trigger" data-testid="share-link-menu-trigger"
variant="plain" variant="plain"
suffixClassName={styles.suffixClassName}
contentStyle={{ contentStyle={{
width: '100%', width: '100%',
}} }}

View File

@@ -3,27 +3,36 @@ import { cssVarV2 } from '@toeverything/theme/v2';
import { style } from '@vanilla-extract/css'; import { style } from '@vanilla-extract/css';
export const menuTriggerStyle = style({ export const menuTriggerStyle = style({
padding: '4px 10px', padding: '4px 0px 4px 4px',
borderRadius: '4px', borderRadius: '4px',
justifyContent: 'space-between', justifyContent: 'space-between',
display: 'flex', display: 'flex',
fontSize: cssVar('fontSm'), fontSize: cssVar('fontSm'),
fontWeight: 400, fontWeight: 400,
height: '30px',
selectors: { selectors: {
'&.disable': { '&.disable': {
alignItems: 'center', alignItems: 'center',
gap: '4px', gap: '4px',
marginRight: '4px',
color: cssVarV2('text/disable'), color: cssVarV2('text/disable'),
}, },
}, },
}); });
export const menuTriggerText = style({
margin: '0px 4px',
});
export const suffixClassName = style({
width: '20px',
height: '20px',
});
export const rowContainerStyle = style({ export const rowContainerStyle = style({
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'space-between', justifyContent: 'space-between',
alignItems: 'center', alignItems: 'center',
padding: '4px', marginLeft: '4px',
}); });
export const exportContainerStyle = style({ export const exportContainerStyle = style({
display: 'flex', display: 'flex',
@@ -32,7 +41,6 @@ export const exportContainerStyle = style({
}); });
export const labelStyle = style({ export const labelStyle = style({
fontSize: cssVar('fontSm'), fontSize: cssVar('fontSm'),
fontWeight: 500,
}); });
export const publicItemRowStyle = style({ export const publicItemRowStyle = style({
display: 'flex', display: 'flex',

View File

@@ -15,6 +15,10 @@ export const content = style({
flexDirection: 'column', flexDirection: 'column',
gap: '8px', gap: '8px',
}); });
export const divider = style({
borderColor: cssVarV2('tab/divider/divider'),
margin: '4px 0px',
});
export const menuStyle = style({ export const menuStyle = style({
width: '390px', width: '390px',
maxHeight: '562px', maxHeight: '562px',
@@ -66,6 +70,13 @@ export const columnContainerStyle = style({
width: '100%', width: '100%',
gap: '8px', gap: '8px',
}); });
export const memberRowsStyle = style({
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
gap: '8px',
margin: '6px 0px',
});
export const exportContainerStyle = style({ export const exportContainerStyle = style({
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
@@ -127,8 +138,9 @@ export const shortcutStyle = style({
}); });
export const generalAccessStyle = style({ export const generalAccessStyle = style({
padding: '4px', padding: '3px 4px',
fontSize: cssVar('fontSm'), fontSize: cssVar('fontSm'),
color: cssVarV2('text/secondary'), color: cssVarV2('text/secondary'),
fontWeight: 500, fontWeight: 500,
height: '30px',
}); });

View File

@@ -2,7 +2,6 @@ import { cssVarV2 } from '@toeverything/theme/v2';
import { style } from '@vanilla-extract/css'; import { style } from '@vanilla-extract/css';
export const inputStyle = style({ export const inputStyle = style({
marginTop: '6px',
padding: '4px', padding: '4px',
gap: '4px', gap: '4px',
borderRadius: '4px', borderRadius: '4px',

View File

@@ -1,4 +1,4 @@
import { Skeleton } from '@affine/component'; import { Divider, Skeleton } from '@affine/component';
import { Button } from '@affine/component/ui/button'; import { Button } from '@affine/component/ui/button';
import { ServerService } from '@affine/core/modules/cloud'; import { ServerService } from '@affine/core/modules/cloud';
import { DocService } from '@affine/core/modules/doc'; import { DocService } from '@affine/core/modules/doc';
@@ -97,8 +97,11 @@ export const AFFiNESharePage = (
return ( return (
<div className={styles.content}> <div className={styles.content}>
<div className={styles.columnContainerStyle}> <div className={styles.columnContainerStyle}>
<div className={styles.memberRowsStyle}>
{canManageUsers && <InviteInput onFocus={props.onClickInvite} />} {canManageUsers && <InviteInput onFocus={props.onClickInvite} />}
<MembersRow onClick={props.onClickMembers} /> <MembersRow onClick={props.onClickMembers} />
</div>
<div className={styles.generalAccessStyle}> <div className={styles.generalAccessStyle}>
{t['com.affine.share-menu.generalAccess']()} {t['com.affine.share-menu.generalAccess']()}
</div> </div>
@@ -109,6 +112,7 @@ export const AFFiNESharePage = (
/> />
<PublicDoc disabled={!canPublish} /> <PublicDoc disabled={!canPublish} />
</div> </div>
<Divider className={styles.divider} />
<CopyLinkButton workspaceId={workspaceId} /> <CopyLinkButton workspaceId={workspaceId} />
</div> </div>
); );