mirror of
https://github.com/lukevella/rallly.git
synced 2025-06-07 13:11:49 +02:00
✨ Use avatar on login page (#1336)
This commit is contained in:
parent
33385f9039
commit
e4b1fee46c
5 changed files with 68 additions and 38 deletions
|
@ -5,9 +5,9 @@ import { useRouter } from "next/navigation";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
|
|
||||||
import { Logo } from "@/components/logo";
|
import { Logo } from "@/components/logo";
|
||||||
|
import { OptimizedAvatarImage } from "@/components/optimized-avatar-image";
|
||||||
import { Skeleton } from "@/components/skeleton";
|
import { Skeleton } from "@/components/skeleton";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { UserAvatar } from "@/components/user";
|
|
||||||
import { usePostHog } from "@/utils/posthog";
|
import { usePostHog } from "@/utils/posthog";
|
||||||
import { trpc } from "@/utils/trpc/client";
|
import { trpc } from "@/utils/trpc/client";
|
||||||
|
|
||||||
|
@ -53,9 +53,13 @@ export const LoginPage = ({ magicLink, email }: PageProps) => {
|
||||||
<div className="mb-4 font-semibold">
|
<div className="mb-4 font-semibold">
|
||||||
<Trans i18nKey="continueAs" defaults="Continue as" />
|
<Trans i18nKey="continueAs" defaults="Continue as" />
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex flex-col items-center gap-2">
|
||||||
|
<OptimizedAvatarImage
|
||||||
|
src={data?.image ?? undefined}
|
||||||
|
name={data?.name ?? ""}
|
||||||
|
size={56}
|
||||||
|
/>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<UserAvatar size="lg" name={data?.name} />
|
|
||||||
<div className="py-4 text-center">
|
|
||||||
<div className="mb-1 h-6 font-medium">
|
<div className="mb-1 h-6 font-medium">
|
||||||
{data?.name ?? <Skeleton className="inline-block h-5 w-16" />}
|
{data?.name ?? <Skeleton className="inline-block h-5 w-16" />}
|
||||||
</div>
|
</div>
|
||||||
|
@ -71,9 +75,8 @@ export const LoginPage = ({ magicLink, email }: PageProps) => {
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await magicLinkFetch.mutateAsync();
|
await magicLinkFetch.mutateAsync();
|
||||||
}}
|
}}
|
||||||
size="lg"
|
|
||||||
variant="primary"
|
variant="primary"
|
||||||
className="mt-4 w-full"
|
className="mt-6 w-full"
|
||||||
>
|
>
|
||||||
<Trans i18nKey="continue" />
|
<Trans i18nKey="continue" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -1,18 +1,8 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from "@rallly/ui/avatar";
|
|
||||||
import Image from "next/image";
|
|
||||||
|
|
||||||
|
import { OptimizedAvatarImage } from "@/components/optimized-avatar-image";
|
||||||
import { useUser } from "@/components/user-provider";
|
import { useUser } from "@/components/user-provider";
|
||||||
|
|
||||||
function getAvatarUrl(imageKey: string) {
|
|
||||||
// Some users have avatars that come from external providers (e.g. Google).
|
|
||||||
if (imageKey.startsWith("https://")) {
|
|
||||||
return imageKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `/api/storage/${imageKey}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CurrentUserAvatar = ({
|
export const CurrentUserAvatar = ({
|
||||||
size,
|
size,
|
||||||
className,
|
className,
|
||||||
|
@ -22,23 +12,11 @@ export const CurrentUserAvatar = ({
|
||||||
}) => {
|
}) => {
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
return (
|
return (
|
||||||
<Avatar className={className} style={{ width: size, height: size }}>
|
<OptimizedAvatarImage
|
||||||
{user.image ? (
|
className={className}
|
||||||
user.image.startsWith("http") ? (
|
src={user.image ?? undefined}
|
||||||
<AvatarImage src={user.image} />
|
name={user.name}
|
||||||
) : (
|
size={size}
|
||||||
<Image
|
|
||||||
src={getAvatarUrl(user.image)}
|
|
||||||
width={128}
|
|
||||||
height={128}
|
|
||||||
alt={user.name}
|
|
||||||
style={{ objectFit: "cover" }}
|
|
||||||
objectFit="cover"
|
|
||||||
/>
|
/>
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<AvatarFallback>{user.name[0]}</AvatarFallback>
|
|
||||||
)}
|
|
||||||
</Avatar>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
45
apps/web/src/components/optimized-avatar-image.tsx
Normal file
45
apps/web/src/components/optimized-avatar-image.tsx
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
"use client";
|
||||||
|
import { Avatar, AvatarFallback, AvatarImage } from "@rallly/ui/avatar";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
function getAvatarUrl(imageKey: string) {
|
||||||
|
// Some users have avatars that come from external providers (e.g. Google).
|
||||||
|
if (imageKey.startsWith("https://")) {
|
||||||
|
return imageKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `/api/storage/${imageKey}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const OptimizedAvatarImage = ({
|
||||||
|
size,
|
||||||
|
className,
|
||||||
|
src,
|
||||||
|
name,
|
||||||
|
}: {
|
||||||
|
size: number;
|
||||||
|
src?: string;
|
||||||
|
name: string;
|
||||||
|
className?: string;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Avatar className={className} style={{ width: size, height: size }}>
|
||||||
|
{src ? (
|
||||||
|
src.startsWith("http") ? (
|
||||||
|
<AvatarImage src={src} alt={name} />
|
||||||
|
) : (
|
||||||
|
<Image
|
||||||
|
src={getAvatarUrl(src)}
|
||||||
|
width={128}
|
||||||
|
height={128}
|
||||||
|
alt={name}
|
||||||
|
style={{ objectFit: "cover" }}
|
||||||
|
objectFit="cover"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<AvatarFallback>{name[0]}</AvatarFallback>
|
||||||
|
)}
|
||||||
|
</Avatar>
|
||||||
|
);
|
||||||
|
};
|
|
@ -43,6 +43,7 @@ export const user = router({
|
||||||
select: {
|
select: {
|
||||||
name: true,
|
name: true,
|
||||||
email: true,
|
email: true,
|
||||||
|
image: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -7,14 +7,17 @@ import { cn } from "@rallly/ui";
|
||||||
|
|
||||||
const Avatar = React.forwardRef<
|
const Avatar = React.forwardRef<
|
||||||
React.ElementRef<typeof AvatarPrimitive.Root>,
|
React.ElementRef<typeof AvatarPrimitive.Root>,
|
||||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
|
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> & {
|
||||||
>(({ className, ...props }, ref) => (
|
size?: number;
|
||||||
|
}
|
||||||
|
>(({ className, size = 48, ...props }, ref) => (
|
||||||
<AvatarPrimitive.Root
|
<AvatarPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex size-10 shrink-0 overflow-hidden rounded-full",
|
"relative flex shrink-0 overflow-hidden rounded-full",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
style={{ width: size, height: size }}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue