Add server avatars. Closes #52

Add identity edit menu. Closes #51
This commit is contained in:
Paul 2021-08-07 22:42:15 +01:00
parent 97816e1feb
commit 4f1ba8942f
10 changed files with 135 additions and 8 deletions

2
external/lang vendored

@ -1 +1 @@
Subproject commit d27cbcf7a8d7663d924ecb67de283b2fea901788
Subproject commit 30558b7989de3b6b39c360d85db4fc58e146ad5e

View file

@ -113,6 +113,7 @@ const Message = observer(
onContextMenu={userContext}
onClick={openProfile}
animate={animate}
showServerIdentity
/>
) : (
<MessageDetail message={message} position="left" />
@ -126,6 +127,7 @@ const Message = observer(
user={user}
onContextMenu={userContext}
onClick={openProfile}
showServerIdentity
/>
<MessageDetail
message={message}

View file

@ -42,7 +42,11 @@ export default function UserHover({ user, children }: Props) {
placement="right-end"
content={
<Base>
<Username className="username" user={user} />
<Username
className="username"
user={user}
showServerIdentity
/>
<span className="status">
<UserStatus user={user} />
</span>

View file

@ -1,5 +1,6 @@
import { MicrophoneOff } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { useParams } from "react-router-dom";
import { Presence } from "revolt-api/types/Users";
import { User } from "revolt.js/dist/maps/Users";
import styled, { css } from "styled-components";
@ -7,7 +8,7 @@ import styled, { css } from "styled-components";
import { useContext } from "preact/hooks";
import { ThemeContext } from "../../../context/Theme";
import { AppContext } from "../../../context/revoltjs/RevoltClient";
import { AppContext, useClient } from "../../../context/revoltjs/RevoltClient";
import IconBase, { IconBaseProps } from "../IconBase";
import fallback from "../assets/user.png";
@ -17,6 +18,7 @@ interface Props extends IconBaseProps<User> {
mask?: string;
status?: boolean;
voice?: VoiceStatus;
showServerIdentity?: boolean;
}
export function useStatusColour(user?: User) {
@ -59,7 +61,7 @@ export default observer(
keyof Props | "children" | "as"
>,
) => {
const client = useContext(AppContext);
const client = useClient();
const {
target,
@ -69,11 +71,28 @@ export default observer(
animate,
mask,
hover,
showServerIdentity,
...svgProps
} = props;
let override;
if (target && showServerIdentity) {
const { server } = useParams<{ server?: string }>();
if (server) {
const member = client.members.getKey({
server,
user: target._id,
});
if (member?.avatar) {
override = member?.avatar;
}
}
}
const iconURL =
client.generateFileURL(
target?.avatar ?? attachment,
override ?? target?.avatar ?? attachment,
{ max_side: 256 },
animate,
) ?? (target ? target.defaultAvatarURL : fallback);

View file

@ -11,12 +11,16 @@ import UserIcon from "./UserIcon";
export const Username = observer(
({
user,
showServerIdentity,
...otherProps
}: { user?: User } & JSX.HTMLAttributes<HTMLElement>) => {
}: {
user?: User;
showServerIdentity?: boolean;
} & JSX.HTMLAttributes<HTMLElement>) => {
let username = user?.username;
let color;
if (user) {
if (user && showServerIdentity) {
const { server } = useParams<{ server?: string }>();
if (server) {
const client = useClient();

View file

@ -64,10 +64,11 @@ export const UserButton = observer((props: UserProps) => {
target={user}
size={32}
status
showServerIdentity
/>
<div className={styles.name}>
<div>
<Username user={user} />
<Username user={user} showServerIdentity />
</div>
{
<div className={styles.subText}>

View file

@ -86,6 +86,10 @@ export type Screen =
id: "user_picker";
omit?: string[];
callback: (users: string[]) => Promise<void>;
}
| {
id: "server_identity";
server: Server;
};
export const IntermediateContext = createContext({

View file

@ -11,6 +11,7 @@ import { ChannelInfo } from "./popovers/ChannelInfo";
import { ImageViewer } from "./popovers/ImageViewer";
import { ModifyAccountModal } from "./popovers/ModifyAccount";
import { PendingRequests } from "./popovers/PendingRequests";
import { ServerIdentityModal } from "./popovers/ServerIdentityModal";
import { UserPicker } from "./popovers/UserPicker";
import { UserProfile } from "./popovers/UserProfile";
@ -40,6 +41,8 @@ export default function Popovers() {
return <SpecialPromptModal onClose={onClose} {...screen} />;
case "special_input":
return <SpecialInputModal onClose={onClose} {...screen} />;
case "server_identity":
return <ServerIdentityModal onClose={onClose} {...screen} />;
}
return null;

View file

@ -0,0 +1,71 @@
import { observer } from "mobx-react-lite";
import { Server } from "revolt.js/dist/maps/Servers";
import { useEffect, useState } from "preact/hooks";
import Button from "../../../components/ui/Button";
import InputBox from "../../../components/ui/InputBox";
import Modal from "../../../components/ui/Modal";
import Overline from "../../../components/ui/Overline";
import { FileUploader } from "../../revoltjs/FileUploads";
import { useClient } from "../../revoltjs/RevoltClient";
interface Props {
server: Server;
onClose: () => void;
}
export const ServerIdentityModal = observer(({ server, onClose }: Props) => {
const client = useClient();
const member = client.members.getKey({
server: server._id,
user: client.user!._id,
});
if (!member) return null;
const [nickname, setNickname] = useState("");
useEffect(() => setNickname(member.nickname ?? ""), [member.nickname]);
return (
<Modal visible={true} onClose={onClose}>
<Overline type="subtle">Nickname</Overline>
<p>
<InputBox
value={nickname}
onChange={(e) => setNickname(e.currentTarget.value)}
/>
</p>
<p>
<Button onClick={() => member.edit({ nickname })}>Save</Button>
</p>
<p>
<Button onClick={() => member.edit({ remove: "Nickname" })}>
Remove
</Button>
</p>
<Overline type="subtle">Avatar</Overline>
<FileUploader
width={80}
height={80}
style="icon"
fileType="avatars"
behaviour="upload"
maxFileSize={4_000_000}
onUpload={(avatar) => member.edit({ avatar })}
remove={() => member.edit({ remove: "Avatar" })}
defaultPreview={client.generateFileURL(
member.avatar ?? undefined,
{ max_side: 256 },
true,
)}
previewURL={client.generateFileURL(
member.avatar ?? undefined,
{ max_side: 256 },
true,
)}
/>
</Modal>
);
});

View file

@ -114,6 +114,7 @@ type Action =
| { action: "close_dm"; target: Channel }
| { action: "leave_server"; target: Server }
| { action: "delete_server"; target: Server }
| { action: "edit_identity"; target: Server }
| { action: "open_notification_options"; channel: Channel }
| { action: "open_settings" }
| { action: "open_channel_settings"; id: string }
@ -408,6 +409,13 @@ function ContextMenus(props: Props) {
} as unknown as Screen);
break;
case "edit_identity":
openScreen({
id: "server_identity",
server: data.target,
});
break;
case "ban_member":
case "kick_member":
openScreen({
@ -850,6 +858,17 @@ function ContextMenus(props: Props) {
}
if (sid && server) {
if (
serverPermissions &
ServerPermission.ChangeNickname ||
serverPermissions &
ServerPermission.ChangeAvatar
)
generateAction(
{ action: "edit_identity", target: server },
"edit_identity",
);
if (
serverPermissions &
ServerPermission.ManageServer