1
0
mirror of https://github.com/spacebarchat/client.git synced 2024-11-25 11:42:30 +01:00

avatar status dots

This commit is contained in:
Puyodead1 2023-12-09 21:01:42 -05:00
parent 95279954b0
commit bcf173563d
No known key found for this signature in database
GPG Key ID: A4FA4FEC0DD353FC
5 changed files with 83 additions and 17 deletions

View File

@ -1,9 +1,11 @@
import { PresenceUpdateStatus } from "@spacebarchat/spacebar-api-types/v9";
import { observer } from "mobx-react-lite";
import React from "react";
import styled from "styled-components";
import { PopoutContext } from "../contexts/PopoutContext";
import AccountStore from "../stores/AccountStore";
import { useAppStore } from "../stores/AppStore";
import Presence from "../stores/objects/Presence";
import User from "../stores/objects/User";
import Container from "./Container";
import UserProfilePopout from "./UserProfilePopout";
@ -11,8 +13,8 @@ import UserProfilePopout from "./UserProfilePopout";
const Wrapper = styled(Container)<{ size: number }>`
width: ${(props) => props.size}px;
height: ${(props) => props.size}px;
border-radius: 50%;
position: relative;
background-color: transparent;
&:hover {
text-decoration: underline;
@ -20,12 +22,28 @@ const Wrapper = styled(Container)<{ size: number }>`
}
`;
const StatusDot = styled.span<{ color: string; width?: number; height?: number }>`
position: absolute;
bottom: 0;
right: 0;
background-color: ${(props) => props.color};
border-radius: 50%;
border: 2px solid var(--background-primary);
width: ${(props) => props.width ?? 10}px;
height: ${(props) => props.height ?? 10}px;
`;
interface Props {
user?: User | AccountStore;
size?: number;
style?: React.CSSProperties;
onClick?: (() => void) | null;
popoutPlacement?: "left" | "right" | "top" | "bottom";
presence?: Presence;
statusDotStyle?: {
width?: number;
height?: number;
};
}
function Avatar(props: Props) {
@ -47,7 +65,7 @@ function Avatar(props: Props) {
if (!rect) return;
popoutContext.open({
element: <UserProfilePopout user={user} />,
element: <UserProfilePopout user={user} presence={props.presence} />,
position: rect,
placement: props.popoutPlacement,
});
@ -57,7 +75,18 @@ function Avatar(props: Props) {
return (
<Wrapper size={props.size ?? 32} style={props.style} ref={ref} {...clickProp}>
<img src={user.avatarUrl} width={props.size ?? 32} height={props.size ?? 32} loading="eager" />
<img
style={{
borderRadius: "50%",
}}
src={user.avatarUrl}
width={props.size ?? 32}
height={props.size ?? 32}
loading="eager"
/>
{props.presence && props.presence.status !== PresenceUpdateStatus.Offline && (
<StatusDot color={app.theme.getStatusColor(props.presence.status)} {...props.statusDotStyle} />
)}
</Wrapper>
);
}

View File

@ -82,7 +82,7 @@ function MemberListItem({ item }: Props) {
e.preventDefault();
e.stopPropagation();
popoutContext.open({
element: <UserProfilePopout user={item.user!} />,
element: <UserProfilePopout user={item.user!} presence={presence} member={item} />,
position: e.currentTarget.getBoundingClientRect(),
placement: "right",
});
@ -91,7 +91,7 @@ function MemberListItem({ item }: Props) {
<Container>
<Wrapper offline={presence?.status === PresenceUpdateStatus.Offline}>
<AvatarWrapper>
<Avatar user={item.user!} size={32} />
<Avatar user={item.user!} size={32} presence={presence} />
</AvatarWrapper>
<TextWrapper>
<Text color={item.roleColor}>{item.nick ?? item.user?.username}</Text>

View File

@ -3,6 +3,8 @@ import styled from "styled-components";
import { ReactComponent as SpacebarLogoBlue } from "../assets/images/logo/Spacebar_Icon.svg";
import useLogger from "../hooks/useLogger";
import AccountStore from "../stores/AccountStore";
import GuildMember from "../stores/objects/GuildMember";
import Presence from "../stores/objects/Presence";
import User from "../stores/objects/User";
import Snowflake from "../utils/Snowflake";
import Avatar from "./Avatar";
@ -80,7 +82,13 @@ const MemberSinceText = styled.span`
font-weight: var(--font-weight-regular);
`;
function UserProfilePopout({ user }: { user: User | AccountStore }) {
interface Props {
user: User | AccountStore;
presence?: Presence;
member?: GuildMember;
}
function UserProfilePopout({ user, presence, member }: Props) {
const logger = useLogger("UserProfilePopout");
// if (!member.user) {
// logger.error("member.user is undefined");
@ -103,6 +111,11 @@ function UserProfilePopout({ user }: { user: User | AccountStore }) {
// TODO: open profile modal
}}
user={user}
presence={presence}
statusDotStyle={{
width: 16,
height: 16,
}}
/>
</Top>
<Bottom>

View File

@ -56,7 +56,9 @@ export type ThemeVariables =
| "warningContrastText"
| "interactive"
| "scrollbarTrack"
| "scrollbarThumb";
| "scrollbarThumb"
| "statusIdle"
| "statusOffline";
export type Overrides = {
[variable in ThemeVariables]: string;
@ -102,13 +104,13 @@ export const ThemePresets: Record<string, Theme> = {
inputBackground: "#757575",
error: "#e83f36",
divider: "#3c3c3c",
primary: "",
primaryLight: "",
primaryDark: "",
primaryContrastText: "",
secondary: "",
secondaryLight: "",
secondaryDark: "",
primary: "#0185ff",
primaryLight: "#339dff",
primaryDark: "#005db2",
primaryContrastText: "#ffffff",
secondary: "#000115",
secondaryLight: "#000677",
secondaryDark: "#000111",
secondaryContrastText: "",
danger: "",
dangerLight: "",
@ -125,6 +127,8 @@ export const ThemePresets: Record<string, Theme> = {
scrollbarTrack: "",
scrollbarThumb: "",
interactive: "",
statusIdle: "#ff7c01",
statusOffline: "#5d5d5d",
font: font,
},
dark: {
@ -149,9 +153,11 @@ export const ThemePresets: Record<string, Theme> = {
primaryLight: "#339dff",
primaryDark: "#005db2",
primaryContrastText: "#ffffff",
secondary: "#ff7c01",
secondaryLight: "#ff9633",
secondaryDark: "#b25600",
secondary: "#000115",
secondaryLight: "#000677",
secondaryDark: "#000111",
// secondary: "#ff7c01",
// secondaryLight: "#ff9633",
secondaryContrastText: "#040404",
danger: "#ff3a3b",
dangerLight: "#ff6162",
@ -168,6 +174,8 @@ export const ThemePresets: Record<string, Theme> = {
scrollbarTrack: "#232323",
scrollbarThumb: "#171717",
interactive: "#424242",
statusIdle: "#ff7c01",
statusOffline: "#5d5d5d",
font: font,
},
};

View File

@ -1,3 +1,4 @@
import { PresenceUpdateStatus } from "@spacebarchat/spacebar-api-types/v9";
import { computed, makeAutoObservable } from "mobx";
import type { Theme } from "../contexts/Theme";
import { ThemePresets } from "../contexts/Theme";
@ -21,4 +22,19 @@ export default class ThemeStore {
return variables as unknown as Theme;
}
@computed
getStatusColor(status?: PresenceUpdateStatus) {
switch (status) {
case PresenceUpdateStatus.Online:
return ThemePresets["dark"].successLight;
case PresenceUpdateStatus.Idle:
return ThemePresets["dark"].statusIdle;
case PresenceUpdateStatus.DoNotDisturb:
return ThemePresets["dark"].dangerLight;
case PresenceUpdateStatus.Offline:
default:
return ThemePresets["dark"].statusOffline;
}
}
}