✨ Use gravatar with user email (#1688)
* ✨ Use gravatar with user email
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
|||||||
IconSun,
|
IconSun,
|
||||||
IconUserCog,
|
IconUserCog,
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
|
import { createHash } from 'crypto';
|
||||||
import { User } from 'next-auth';
|
import { User } from 'next-auth';
|
||||||
import { signOut, useSession } from 'next-auth/react';
|
import { signOut, useSession } from 'next-auth/react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
@@ -26,66 +27,64 @@ export const AvatarMenu = () => {
|
|||||||
const defaultBoardHref = useBoardLink('/board');
|
const defaultBoardHref = useBoardLink('/board');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<UnstyledButton>
|
||||||
<UnstyledButton>
|
<Menu width={256}>
|
||||||
<Menu width={256}>
|
<Menu.Target>
|
||||||
<Menu.Target>
|
<CurrentUserAvatar user={sessionData?.user ?? null} />
|
||||||
<CurrentUserAvatar user={sessionData?.user ?? null} />
|
</Menu.Target>
|
||||||
</Menu.Target>
|
<Menu.Dropdown>
|
||||||
<Menu.Dropdown>
|
<Menu.Item
|
||||||
<Menu.Item
|
closeMenuOnClick={false}
|
||||||
closeMenuOnClick={false}
|
icon={<Icon size="1rem" />}
|
||||||
icon={<Icon size="1rem" />}
|
onClick={toggleColorScheme}
|
||||||
onClick={toggleColorScheme}
|
>
|
||||||
>
|
{t('actions.avatar.switchTheme')}
|
||||||
{t('actions.avatar.switchTheme')}
|
</Menu.Item>
|
||||||
</Menu.Item>
|
{sessionData?.user && (
|
||||||
{sessionData?.user && (
|
<>
|
||||||
<>
|
|
||||||
<Menu.Item
|
|
||||||
component={Link}
|
|
||||||
passHref
|
|
||||||
href="/user/preferences"
|
|
||||||
icon={<IconUserCog size="1rem" />}
|
|
||||||
>
|
|
||||||
{t('actions.avatar.preferences')}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item
|
|
||||||
component={Link}
|
|
||||||
href={defaultBoardHref}
|
|
||||||
icon={<IconDashboard size="1rem" />}
|
|
||||||
>
|
|
||||||
{t('actions.avatar.defaultBoard')}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item component={Link} href="/manage" icon={<IconHomeShare size="1rem" />}>
|
|
||||||
{t('actions.avatar.manage')}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Divider />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{sessionData?.user ? (
|
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
icon={<IconLogout size="1rem" />}
|
component={Link}
|
||||||
color="red"
|
passHref
|
||||||
onClick={() =>
|
href="/user/preferences"
|
||||||
signOut({
|
icon={<IconUserCog size="1rem" />}
|
||||||
redirect: false,
|
|
||||||
}).then(() => window.location.reload())
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{t('actions.avatar.logout', {
|
{t('actions.avatar.preferences')}
|
||||||
username: sessionData.user.name,
|
|
||||||
})}
|
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
) : (
|
<Menu.Item
|
||||||
<Menu.Item icon={<IconLogin size="1rem" />} component={Link} href="/auth/login">
|
component={Link}
|
||||||
{t('actions.avatar.login')}
|
href={defaultBoardHref}
|
||||||
|
icon={<IconDashboard size="1rem" />}
|
||||||
|
>
|
||||||
|
{t('actions.avatar.defaultBoard')}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
)}
|
<Menu.Item component={Link} href="/manage" icon={<IconHomeShare size="1rem" />}>
|
||||||
</Menu.Dropdown>
|
{t('actions.avatar.manage')}
|
||||||
</Menu>
|
</Menu.Item>
|
||||||
</UnstyledButton>
|
<Menu.Divider />
|
||||||
</>
|
</>
|
||||||
|
)}
|
||||||
|
{sessionData?.user ? (
|
||||||
|
<Menu.Item
|
||||||
|
icon={<IconLogout size="1rem" />}
|
||||||
|
color="red"
|
||||||
|
onClick={() =>
|
||||||
|
signOut({
|
||||||
|
redirect: false,
|
||||||
|
}).then(() => window.location.reload())
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t('actions.avatar.logout', {
|
||||||
|
username: sessionData.user.name,
|
||||||
|
})}
|
||||||
|
</Menu.Item>
|
||||||
|
) : (
|
||||||
|
<Menu.Item icon={<IconLogin size="1rem" />} component={Link} href="/auth/login">
|
||||||
|
{t('actions.avatar.login')}
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
</Menu.Dropdown>
|
||||||
|
</Menu>
|
||||||
|
</UnstyledButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -93,12 +92,29 @@ type CurrentUserAvatarProps = {
|
|||||||
user: User | null;
|
user: User | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getGravatar = (email?: string | undefined | null) => {
|
||||||
|
if (!email) return null;
|
||||||
|
const emailHash = createHash('sha256').update(email.trim().toLowerCase()).digest('hex');
|
||||||
|
return `https://gravatar.com/avatar/${emailHash}?d=null`;
|
||||||
|
};
|
||||||
|
|
||||||
const CurrentUserAvatar = forwardRef<HTMLDivElement, CurrentUserAvatarProps>(
|
const CurrentUserAvatar = forwardRef<HTMLDivElement, CurrentUserAvatarProps>(
|
||||||
({ user, ...others }, ref) => {
|
({ user, ...others }, ref) => {
|
||||||
const { primaryColor } = useMantineTheme();
|
const { primaryColor } = useMantineTheme();
|
||||||
if (!user) return <Avatar ref={ref} {...others} />;
|
const { fn } = useMantineTheme();
|
||||||
|
const border = fn.variant({ variant: 'default' }).border;
|
||||||
|
|
||||||
|
if (!user)
|
||||||
|
return <Avatar ref={ref} styles={{ root: { border: `1px solid ${border}` } }} {...others} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Avatar ref={ref} color={primaryColor} {...others}>
|
<Avatar
|
||||||
|
ref={ref}
|
||||||
|
color={primaryColor}
|
||||||
|
src={getGravatar(user.email)}
|
||||||
|
styles={{ root: { border: `1px solid ${border}` } }}
|
||||||
|
{...others}
|
||||||
|
>
|
||||||
{user.name?.slice(0, 2).toUpperCase()}
|
{user.name?.slice(0, 2).toUpperCase()}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user