2021-06-27 06:17:59 -04:00
|
|
|
import { MicrophoneOff } from "@styled-icons/boxicons-regular";
|
2021-07-05 06:23:23 -04:00
|
|
|
import { User } from "revolt.js";
|
2021-06-19 07:34:53 -04:00
|
|
|
import { Users } from "revolt.js/dist/api/objects";
|
2021-07-05 06:23:23 -04:00
|
|
|
import styled, { css } from "styled-components";
|
|
|
|
|
|
|
|
import { useContext } from "preact/hooks";
|
|
|
|
|
2021-06-20 15:30:42 -04:00
|
|
|
import { ThemeContext } from "../../../context/Theme";
|
|
|
|
import { AppContext } from "../../../context/revoltjs/RevoltClient";
|
2021-06-19 07:34:53 -04:00
|
|
|
|
2021-07-05 06:23:23 -04:00
|
|
|
import IconBase, { IconBaseProps } from "../IconBase";
|
|
|
|
import fallback from "../assets/user.png";
|
|
|
|
|
2021-06-19 07:34:53 -04:00
|
|
|
type VoiceStatus = "muted";
|
|
|
|
interface Props extends IconBaseProps<User> {
|
2021-07-05 06:23:23 -04:00
|
|
|
mask?: string;
|
|
|
|
status?: boolean;
|
|
|
|
voice?: VoiceStatus;
|
2021-06-19 07:34:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
export function useStatusColour(user?: User) {
|
2021-07-05 06:23:23 -04:00
|
|
|
const theme = useContext(ThemeContext);
|
2021-06-19 07:34:53 -04:00
|
|
|
|
2021-07-05 06:23:23 -04:00
|
|
|
return user?.online && user?.status?.presence !== Users.Presence.Invisible
|
|
|
|
? user?.status?.presence === Users.Presence.Idle
|
|
|
|
? theme["status-away"]
|
|
|
|
: user?.status?.presence === Users.Presence.Busy
|
|
|
|
? theme["status-busy"]
|
|
|
|
: theme["status-online"]
|
|
|
|
: theme["status-invisible"];
|
2021-06-19 07:34:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
const VoiceIndicator = styled.div<{ status: VoiceStatus }>`
|
2021-07-05 06:23:23 -04:00
|
|
|
width: 10px;
|
|
|
|
height: 10px;
|
|
|
|
border-radius: 50%;
|
2021-06-19 07:34:53 -04:00
|
|
|
|
2021-07-05 06:23:23 -04:00
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
2021-06-19 07:34:53 -04:00
|
|
|
|
2021-07-05 06:23:23 -04:00
|
|
|
svg {
|
|
|
|
stroke: white;
|
|
|
|
}
|
2021-06-19 07:34:53 -04:00
|
|
|
|
2021-07-05 06:23:23 -04:00
|
|
|
${(props) =>
|
|
|
|
props.status === "muted" &&
|
|
|
|
css`
|
|
|
|
background: var(--error);
|
|
|
|
`}
|
2021-06-19 07:34:53 -04:00
|
|
|
`;
|
|
|
|
|
2021-07-05 06:23:23 -04:00
|
|
|
export default function UserIcon(
|
|
|
|
props: Props & Omit<JSX.SVGAttributes<SVGSVGElement>, keyof Props>,
|
|
|
|
) {
|
|
|
|
const client = useContext(AppContext);
|
2021-06-19 07:34:53 -04:00
|
|
|
|
2021-07-05 06:23:23 -04:00
|
|
|
const {
|
|
|
|
target,
|
|
|
|
attachment,
|
|
|
|
size,
|
|
|
|
voice,
|
|
|
|
status,
|
|
|
|
animate,
|
|
|
|
mask,
|
|
|
|
children,
|
|
|
|
as,
|
|
|
|
...svgProps
|
|
|
|
} = props;
|
|
|
|
const iconURL =
|
|
|
|
client.generateFileURL(
|
|
|
|
target?.avatar ?? attachment,
|
|
|
|
{ max_side: 256 },
|
|
|
|
animate,
|
|
|
|
) ?? (target ? client.users.getDefaultAvatarURL(target._id) : fallback);
|
2021-06-19 07:34:53 -04:00
|
|
|
|
2021-07-05 06:23:23 -04:00
|
|
|
return (
|
|
|
|
<IconBase
|
|
|
|
{...svgProps}
|
|
|
|
width={size}
|
|
|
|
height={size}
|
|
|
|
aria-hidden="true"
|
|
|
|
viewBox="0 0 32 32">
|
|
|
|
<foreignObject
|
|
|
|
x="0"
|
|
|
|
y="0"
|
|
|
|
width="32"
|
|
|
|
height="32"
|
|
|
|
mask={mask ?? (status ? "url(#user)" : undefined)}>
|
|
|
|
{<img src={iconURL} draggable={false} />}
|
|
|
|
</foreignObject>
|
|
|
|
{props.status && (
|
|
|
|
<circle cx="27" cy="27" r="5" fill={useStatusColour(target)} />
|
|
|
|
)}
|
|
|
|
{props.voice && (
|
|
|
|
<foreignObject x="22" y="22" width="10" height="10">
|
|
|
|
<VoiceIndicator status={props.voice}>
|
|
|
|
{props.voice === "muted" && <MicrophoneOff size={6} />}
|
|
|
|
</VoiceIndicator>
|
|
|
|
</foreignObject>
|
|
|
|
)}
|
|
|
|
</IconBase>
|
|
|
|
);
|
2021-06-19 07:34:53 -04:00
|
|
|
}
|