9deb320cf6
Rename the global Sidebar route, UI, assets, analytics, and payment return context to Profile. Add accessible message-avatar navigation and preserve the source character across auth and logout flows. BREAKING CHANGE: /sidebar has been removed; use /profile instead.
73 lines
1.9 KiB
TypeScript
73 lines
1.9 KiB
TypeScript
"use client";
|
|
|
|
import Image from "next/image";
|
|
|
|
import type { AvatarInteractionProps } from "./avatar-interaction";
|
|
|
|
interface UserMessageAvatarVisualProps {
|
|
avatarUrl?: string | null;
|
|
className?: string;
|
|
size?: number | string;
|
|
}
|
|
|
|
export type UserMessageAvatarProps = UserMessageAvatarVisualProps &
|
|
AvatarInteractionProps;
|
|
|
|
export function UserMessageAvatar({
|
|
avatarUrl,
|
|
className,
|
|
size = 43,
|
|
onClick,
|
|
actionLabel,
|
|
analyticsKey,
|
|
}: UserMessageAvatarProps) {
|
|
const avatarClassName = [
|
|
"flex shrink-0 items-center justify-center overflow-hidden rounded-full border-2 border-(--color-avatar-border,#fbf3f5) bg-(--color-avatar-border,#fbf3f5) shadow-(--shadow-input-box,0_1px_2px_rgba(0,0,0,0.1))",
|
|
onClick
|
|
? "cursor-pointer p-0 transition-transform duration-150 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-accent active:scale-96"
|
|
: undefined,
|
|
className,
|
|
]
|
|
.filter(Boolean)
|
|
.join(" ");
|
|
const avatarStyle = { width: size, height: size };
|
|
const imageSize = typeof size === "number" ? size : 64;
|
|
|
|
const hasUserAvatar = Boolean(avatarUrl && avatarUrl.length > 0);
|
|
const image = (
|
|
<Image
|
|
src={hasUserAvatar ? avatarUrl! : "/images/avatar/placeholder.png"}
|
|
alt={hasUserAvatar ? "" : "Guest"}
|
|
width={imageSize}
|
|
height={imageSize}
|
|
className="size-full object-cover"
|
|
/>
|
|
);
|
|
|
|
if (onClick) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
className={avatarClassName}
|
|
style={avatarStyle}
|
|
aria-label={actionLabel}
|
|
data-analytics-key={analyticsKey}
|
|
data-analytics-label={actionLabel}
|
|
onClick={onClick}
|
|
>
|
|
{image}
|
|
</button>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className={avatarClassName}
|
|
style={avatarStyle}
|
|
aria-label={hasUserAvatar ? "User avatar" : "Guest avatar"}
|
|
>
|
|
{image}
|
|
</div>
|
|
);
|
|
}
|