feat: modify 404 page (#4383)
This commit is contained in:
@@ -1,46 +1,37 @@
|
|||||||
import { displayFlex, styled } from '@affine/component';
|
import { NotFoundPage } from '@affine/component/not-found-page';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||||
import { Button } from '@toeverything/components/button';
|
import { useSession } from 'next-auth/react';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { useNavigateHelper } from '../hooks/use-navigate-helper';
|
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
|
||||||
|
import { signOutCloud } from '../utils/cloud-utils';
|
||||||
export const StyledContainer = styled('div')(() => {
|
|
||||||
return {
|
|
||||||
...displayFlex('center', 'center'),
|
|
||||||
flexDirection: 'column',
|
|
||||||
height: '100vh',
|
|
||||||
|
|
||||||
img: {
|
|
||||||
width: '360px',
|
|
||||||
height: '270px',
|
|
||||||
},
|
|
||||||
p: {
|
|
||||||
fontSize: '22px',
|
|
||||||
fontWeight: 600,
|
|
||||||
margin: '24px 0',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const NotFoundPage = () => {
|
|
||||||
const t = useAFFiNEI18N();
|
|
||||||
const { jumpToIndex } = useNavigateHelper();
|
|
||||||
const handleBackButtonClick = useCallback(() => jumpToIndex(), [jumpToIndex]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledContainer data-testid="notFound">
|
|
||||||
<img alt="404" src="/imgs/invite-error.svg" width={360} height={270} />
|
|
||||||
|
|
||||||
<p>{t['com.affine.notFoundPage.title']()}</p>
|
|
||||||
<Button onClick={handleBackButtonClick}>
|
|
||||||
{t['com.affine.notFoundPage.backButton']()}
|
|
||||||
</Button>
|
|
||||||
</StyledContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Component = (): ReactElement => {
|
export const Component = (): ReactElement => {
|
||||||
return <NotFoundPage />;
|
const { data: session } = useSession();
|
||||||
|
const { jumpToIndex } = useNavigateHelper();
|
||||||
|
const handleBackButtonClick = useCallback(
|
||||||
|
() => jumpToIndex(RouteLogic.REPLACE),
|
||||||
|
[jumpToIndex]
|
||||||
|
);
|
||||||
|
const handleSignOut = useCallback(async () => {
|
||||||
|
await signOutCloud({
|
||||||
|
callbackUrl: '/signIn',
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<NotFoundPage
|
||||||
|
user={
|
||||||
|
session?.user
|
||||||
|
? {
|
||||||
|
name: session.user.name || '',
|
||||||
|
email: session.user.email || '',
|
||||||
|
avatar: session.user.image || '',
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
onBack={handleBackButtonClick}
|
||||||
|
onSignOut={handleSignOut}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './not-found-page';
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
|
import { SignOutIcon } from '@blocksuite/icons';
|
||||||
|
import { Avatar } from '@toeverything/components/avatar';
|
||||||
|
import { Button, IconButton } from '@toeverything/components/button';
|
||||||
|
import { Tooltip } from '@toeverything/components/tooltip';
|
||||||
|
|
||||||
|
import { NotFoundPattern } from './not-found-pattern';
|
||||||
|
import { notFoundPageContainer, wrapper } from './styles.css';
|
||||||
|
|
||||||
|
export interface NotFoundPageProps {
|
||||||
|
user: {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
avatar: string;
|
||||||
|
} | null;
|
||||||
|
onBack: () => void;
|
||||||
|
onSignOut: () => void;
|
||||||
|
}
|
||||||
|
export const NotFoundPage = ({
|
||||||
|
user,
|
||||||
|
onBack,
|
||||||
|
onSignOut,
|
||||||
|
}: NotFoundPageProps) => {
|
||||||
|
const t = useAFFiNEI18N();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={notFoundPageContainer}>
|
||||||
|
<div>
|
||||||
|
<div className={wrapper}>
|
||||||
|
<NotFoundPattern />
|
||||||
|
</div>
|
||||||
|
<div className={wrapper}>
|
||||||
|
<Button type="primary" size="extraLarge" onClick={onBack}>
|
||||||
|
{t['404.back']()}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<p className={wrapper}>{t['404.hint']()}</p>
|
||||||
|
{user ? (
|
||||||
|
<div className={wrapper}>
|
||||||
|
<Avatar url={user.avatar} name={user.name} />
|
||||||
|
<span style={{ margin: '0 12px' }}>{user.email}</span>
|
||||||
|
<Tooltip content={t['404.signOut']()}>
|
||||||
|
<IconButton onClick={onSignOut}>
|
||||||
|
<SignOutIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
export const NotFoundPattern = () => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="240"
|
||||||
|
height="209"
|
||||||
|
viewBox="0 0 240 209"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M24.4197 172.91L119.045 8.64233L213.671 172.91H24.4197Z"
|
||||||
|
stroke="var(--affine-text-disable-color)"
|
||||||
|
strokeOpacity="0.6"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M165.921 91.5342L119.045 172.161L72.1684 91.5342L165.921 91.5342Z"
|
||||||
|
stroke="var(--affine-text-disable-color)"
|
||||||
|
strokeOpacity="0.6"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M179.022 68.1181C179.022 101.243 152.169 128.096 119.045 128.096C85.9202 128.096 59.0674 101.243 59.0674 68.1181C59.0674 34.9934 85.9202 8.14062 119.045 8.14062C152.169 8.14062 179.022 34.9934 179.022 68.1181Z"
|
||||||
|
stroke="var(--affine-text-disable-color)"
|
||||||
|
strokeOpacity="0.6"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="162.485"
|
||||||
|
cy="142.984"
|
||||||
|
r="59.9775"
|
||||||
|
transform="rotate(120 162.485 142.984)"
|
||||||
|
stroke="var(--affine-text-disable-color)"
|
||||||
|
strokeOpacity="0.6"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="75.2925"
|
||||||
|
cy="142.984"
|
||||||
|
r="59.9775"
|
||||||
|
transform="rotate(-120 75.2925 142.984)"
|
||||||
|
stroke="var(--affine-text-disable-color)"
|
||||||
|
strokeOpacity="0.6"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M119.045 7.64062V173.158"
|
||||||
|
stroke="var(--affine-text-disable-color)"
|
||||||
|
strokeOpacity="0.6"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M214.536 173.475L71.2998 91.0352"
|
||||||
|
stroke="var(--affine-text-disable-color)"
|
||||||
|
strokeOpacity="0.6"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M23.5547 173.475L166.791 91.0352"
|
||||||
|
stroke="var(--affine-text-disable-color)"
|
||||||
|
strokeOpacity="0.6"
|
||||||
|
/>
|
||||||
|
<ellipse
|
||||||
|
cx="119.045"
|
||||||
|
cy="7.63971"
|
||||||
|
rx="5.09284"
|
||||||
|
ry="5.09284"
|
||||||
|
fill="var(--affine-text-primary-color)"
|
||||||
|
/>
|
||||||
|
<ellipse
|
||||||
|
cx="214.536"
|
||||||
|
cy="173.155"
|
||||||
|
rx="5.09284"
|
||||||
|
ry="5.09284"
|
||||||
|
fill="var(--affine-text-primary-color)"
|
||||||
|
/>
|
||||||
|
<ellipse
|
||||||
|
cx="166.79"
|
||||||
|
cy="91.0342"
|
||||||
|
rx="5.09284"
|
||||||
|
ry="5.09284"
|
||||||
|
fill="var(--affine-text-primary-color)"
|
||||||
|
/>
|
||||||
|
<ellipse
|
||||||
|
cx="119.045"
|
||||||
|
cy="173.155"
|
||||||
|
rx="5.09284"
|
||||||
|
ry="5.09284"
|
||||||
|
fill="var(--affine-text-primary-color)"
|
||||||
|
/>
|
||||||
|
<ellipse
|
||||||
|
cx="71.2999"
|
||||||
|
cy="91.0342"
|
||||||
|
rx="5.09284"
|
||||||
|
ry="5.09284"
|
||||||
|
fill="var(--affine-text-primary-color)"
|
||||||
|
/>
|
||||||
|
<ellipse
|
||||||
|
cx="119.045"
|
||||||
|
cy="91.0342"
|
||||||
|
rx="5.09284"
|
||||||
|
ry="5.09284"
|
||||||
|
fill="var(--affine-text-primary-color)"
|
||||||
|
/>
|
||||||
|
<ellipse
|
||||||
|
cx="95.4903"
|
||||||
|
cy="131.776"
|
||||||
|
rx="5.09284"
|
||||||
|
ry="5.09284"
|
||||||
|
fill="var(--affine-text-primary-color)"
|
||||||
|
/>
|
||||||
|
<ellipse
|
||||||
|
cx="143.236"
|
||||||
|
cy="131.776"
|
||||||
|
rx="5.09284"
|
||||||
|
ry="5.09284"
|
||||||
|
fill="var(--affine-text-primary-color)"
|
||||||
|
/>
|
||||||
|
<ellipse
|
||||||
|
cx="23.5548"
|
||||||
|
cy="173.155"
|
||||||
|
rx="5.09284"
|
||||||
|
ry="5.09284"
|
||||||
|
fill="var(--affine-text-primary-color)"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
|
export const notFoundPageContainer = style({
|
||||||
|
fontSize: 'var(--affine-font-base)',
|
||||||
|
color: 'var(--affine-text-primary-color)',
|
||||||
|
height: '100vh',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: '100vw',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const wrapper = style({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
margin: '24px auto 0',
|
||||||
|
});
|
||||||
@@ -574,5 +574,8 @@
|
|||||||
"Click to replace photo": "Click to replace photo",
|
"Click to replace photo": "Click to replace photo",
|
||||||
"Remove photo": "Remove photo",
|
"Remove photo": "Remove photo",
|
||||||
"Removed successfully": "Removed successfully",
|
"Removed successfully": "Removed successfully",
|
||||||
"Successfully enabled AFFiNE Cloud": "Successfully enabled AFFiNE Cloud"
|
"Successfully enabled AFFiNE Cloud": "Successfully enabled AFFiNE Cloud",
|
||||||
|
"404.hint": "Sorry, you do not have access or this content does not exist...",
|
||||||
|
"404.back": "Back to My Content",
|
||||||
|
"404.signOut": "Sign in to another account"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user