This commit is contained in:
yohlo
2026-07-14 00:12:39 -07:00
parent e6c72a5789
commit d3809b5805
17 changed files with 504 additions and 168 deletions
+53 -90
View File
@@ -1,36 +1,27 @@
import { useState, useEffect, useRef } from "react";
import { Paper, Box } from "@mantine/core";
import {
Avatar as MantineAvatar,
AvatarProps as MantineAvatarProps,
} from "@mantine/core";
import { Box, Avatar as MantineAvatar } from "@mantine/core";
interface GlitchAvatarProps
extends Omit<MantineAvatarProps, "radius" | "color" | "size"> {
interface GlitchAvatarProps {
name: string;
src?: string;
glitchSrc?: string;
size?: number;
radius?: string | number;
withBorder?: boolean;
contain?: boolean;
children?: React.ReactNode;
px?: string | number;
frame?: boolean;
}
const FRAME_PADDING = 8;
const toCssRadius = (radius: string | number) =>
typeof radius === "number" ? `${radius}px` : `var(--mantine-radius-${radius})`;
const GlitchAvatar = ({
name,
src,
glitchSrc,
size = 35,
radius = "100%",
withBorder = true,
contain = false,
radius = "md",
children,
px,
frame = false,
...props
}: GlitchAvatarProps) => {
const [showGlitch, setShowGlitch] = useState(false);
const [isPlaying, setIsPlaying] = useState(false);
@@ -90,98 +81,70 @@ const GlitchAvatar = ({
});
}, [showGlitch, isPlaying]);
const innerRadius = toCssRadius(radius);
return (
<Box
style={{
padding: "8px",
borderRadius:
typeof radius === "number"
? `${radius + 8}px`
: "calc(var(--mantine-radius-md) + 8px)",
position: "relative",
...(frame && {
boxShadow:
"0 0 0 1px color-mix(in srgb, var(--mantine-primary-color-filled) 35%, transparent), 0 8px 32px -8px color-mix(in srgb, var(--mantine-primary-color-filled) 30%, transparent)",
}),
width: "fit-content",
padding: FRAME_PADDING,
border: "1px solid var(--mantine-color-default-border)",
borderRadius: `calc(${innerRadius} + ${FRAME_PADDING}px)`,
}}
>
<Box
style={{
opacity: showGlitch ? 0 : 1,
transition: showGlitch
? "opacity 0.05s ease-in"
: "opacity 0.25s ease-out",
}}
>
<Paper
py={size / 12.5}
px={size / 20}
bg="var(--mantine-color-default-border)"
radius={radius}
withBorder={false}
style={{
cursor: "default",
}}
>
<MantineAvatar
alt={name}
key={name}
name={name}
color="initials"
size={size}
radius={radius}
w={size}
styles={{
image: {
objectFit: contain ? "contain" : "cover",
},
}}
{src ? (
<Box style={{ position: "relative" }}>
<img
src={src}
{...props}
>
{children}
</MantineAvatar>
</Paper>
</Box>
{glitchSrc && (
<Box
style={{
position: "absolute",
top: "8px",
left: "8px",
opacity: showGlitch ? 1 : 0,
visibility: showGlitch ? "visible" : "hidden",
transition: showGlitch ? "opacity 0.05s ease-in" : "none",
pointerEvents: "none",
}}
>
<Paper
py={size / 12.5}
px={size / 20}
bg="var(--mantine-color-default-border)"
radius={radius}
withBorder={false}
alt={name}
style={{
overflow: "hidden",
display: "block",
maxWidth: size,
maxHeight: size,
width: "auto",
height: "auto",
borderRadius: innerRadius,
opacity: showGlitch ? 0 : 1,
transition: showGlitch
? "opacity 0.05s ease-in"
: "opacity 0.25s ease-out",
}}
>
/>
{glitchSrc && (
<video
ref={videoRef}
src={glitchSrc}
style={{
width: `${size}px`,
height: `${size}px`,
objectFit: contain ? "contain" : "cover",
borderRadius: typeof radius === "number" ? `${radius}px` : radius,
display: "block",
position: "absolute",
inset: 0,
width: "100%",
height: "100%",
objectFit: "contain",
borderRadius: innerRadius,
opacity: showGlitch ? 1 : 0,
visibility: showGlitch ? "visible" : "hidden",
transition: showGlitch ? "opacity 0.05s ease-in" : "none",
pointerEvents: "none",
}}
muted
playsInline
preload="auto"
/>
</Paper>
)}
</Box>
) : (
<MantineAvatar
alt={name}
key={name}
name={name}
color="initials"
size={size}
radius={radius}
w={size}
>
{children}
</MantineAvatar>
)}
</Box>
);