feat(modal): implement new server identity modal

closes #172
This commit is contained in:
Paul Makles
2022-06-18 15:54:17 +01:00
parent f685352963
commit 03e177f865
11 changed files with 171 additions and 145 deletions

View File

@@ -3,7 +3,13 @@ import { useHistory } from "react-router-dom";
import { API, Channel, Message, Server, User } from "revolt.js";
import { createContext } from "preact";
import { useContext, useEffect, useMemo, useState } from "preact/hooks";
import {
StateUpdater,
useContext,
useEffect,
useMemo,
useState,
} from "preact/hooks";
import type { Action } from "@revoltchat/ui/esm/components/design/atoms/display/Modal";
@@ -128,12 +134,11 @@ interface Props {
children: Children;
}
export let __thisIsAHack;
export let __thisIsAHack: StateUpdater<Screen>;
export default function Intermediate(props: Props) {
const [screen, openScreen] = useState<Screen>({ id: "none" });
__thisIsAHack = openScreen;
const settings = useApplicationState().settings;
const history = useHistory();
const value = {

View File

@@ -1,14 +1,11 @@
import { useContext } from "preact/hooks";
import { internalEmit } from "../../lib/eventEmitter";
import { IntermediateContext, useIntermediate } from "./Intermediate";
import { SpecialInputModal } from "./modals/Input";
import { SpecialPromptModal } from "./modals/Prompt";
import { ChannelInfo } from "./popovers/ChannelInfo";
import { CreateBotModal } from "./popovers/CreateBot";
import { ImageViewer } from "./popovers/ImageViewer";
import { ServerIdentityModal } from "./popovers/ServerIdentityModal";
import { UserPicker } from "./popovers/UserPicker";
import { UserProfile } from "./popovers/UserProfile";
@@ -42,9 +39,6 @@ export default function Popovers() {
case "special_input":
// @ts-expect-error someone figure this out :)
return <SpecialInputModal onClose={onClose} {...screen} />;
case "server_identity":
// @ts-expect-error someone figure this out :)
return <ServerIdentityModal onClose={onClose} {...screen} />;
}
return null;

View File

@@ -1,17 +0,0 @@
.identityMain {
display: flex;
flex-direction: row;
gap: 10px;
> div {
display: flex;
flex-direction: column;
gap: 10px;
}
.buttons {
display: flex;
flex-direction: row;
gap: 10px;
}
}

View File

@@ -1,106 +0,0 @@
import { observer } from "mobx-react-lite";
import { Server } from "revolt.js";
import styles from "./ServerIdentityModal.module.scss";
import { Text } from "preact-i18n";
import { useEffect, useState } from "preact/hooks";
import { Button, Category, InputBox, Modal } from "@revoltchat/ui";
import { noop } from "../../../lib/js";
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("");
const [currentNickname, setCurrentNickname] = useState("");
useEffect(() => {
setNickname(member.nickname ?? "");
setCurrentNickname(member.nickname ?? "");
}, [member.nickname]);
return (
<Modal
title={
<Text
id={"app.special.popovers.server_identity.title"}
fields={{ server: server.name }}
/>
}
onClose={onClose}>
<div className={styles.identityMain}>
<div>
<Category>
<Text id="app.special.popovers.server_identity.avatar" />
</Category>
<FileUploader
width={80}
height={80}
style="icon"
fileType="avatars"
behaviour="upload"
maxFileSize={4_000_000}
onUpload={(avatar) =>
member.edit({ avatar }).then(noop)
}
remove={() =>
member.edit({ remove: ["Avatar"] }).then(noop)
}
defaultPreview={client.user?.generateAvatarURL(
{
max_side: 256,
},
false,
)}
previewURL={client.generateFileURL(
member.avatar ?? undefined,
{ max_side: 256 },
true,
)}
desaturateDefault
/>
</div>
<div>
<Category>
<Text id="app.special.popovers.server_identity.nickname" />
</Category>
<InputBox
value={nickname}
placeholder={client.user!.username}
onChange={(e) => setNickname(e.currentTarget.value)}
/>
<div className={styles.buttons}>
<Button
disabled={nickname === currentNickname}
onClick={() => member.edit({ nickname })}>
<Text id="app.special.modals.actions.save" />
</Button>
{currentNickname !== "" && (
<Button
palette="plain"
onClick={() =>
member.edit({ remove: ["Nickname"] })
}>
<Text id="app.special.modals.actions.remove" />
</Button>
)}
</div>
</div>
</div>
</Modal>
);
});

View File

@@ -0,0 +1,138 @@
import { X } from "@styled-icons/boxicons-regular";
import { Save } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import styled from "styled-components";
import { Text } from "preact-i18n";
import { useMemo, useState } from "preact/hooks";
import {
Button,
Category,
Centred,
Column,
InputBox,
Modal,
Row,
Message,
} from "@revoltchat/ui";
import { noop } from "../../../lib/js";
import { FileUploader } from "../../revoltjs/FileUploads";
import { ModalProps } from "../types";
const Preview = styled(Centred)`
flex-grow: 1;
border-radius: var(--border-radius);
background: var(--secondary-background);
> div {
padding: 0;
}
`;
export default observer(
({ member, ...props }: ModalProps<"server_identity">) => {
const [nickname, setNickname] = useState(member.nickname ?? "");
const message: any = useMemo(() => {
return {
author: member.user!,
member: {
...member,
nickname,
},
};
}, []);
return (
<Modal
{...props}
title={
<Text
id={"app.special.popovers.server_identity.title"}
fields={{ server: member.server!.name }}
/>
}>
<Column gap="18px">
<Column>
<Category compact>
<Text id="app.special.popovers.server_identity.nickname" />
</Category>
<Row centred>
<InputBox
value={nickname}
placeholder={member.user!.username}
onChange={(e) =>
setNickname(e.currentTarget.value)
}
/>
<Button
compact="icon"
palette="secondary"
disabled={
nickname === member.nickname || !nickname
}
onClick={() => member.edit({ nickname })}>
<Save size={24} />
</Button>
<Button
compact="icon"
palette="secondary"
disabled={!member.nickname}
onClick={() =>
member
.edit({ remove: ["Nickname"] })
.then(() => setNickname(""))
}>
<X size={24} />
</Button>
</Row>
</Column>
<Row gap="18px">
<Column>
<Category compact>
<Text id="app.special.popovers.server_identity.avatar" />
</Category>
<FileUploader
width={80}
height={80}
style="icon"
fileType="avatars"
behaviour="upload"
maxFileSize={4_000_000}
onUpload={(avatar) =>
member.edit({ avatar }).then(noop)
}
remove={() =>
member
.edit({ remove: ["Avatar"] })
.then(noop)
}
defaultPreview={member.user?.generateAvatarURL(
{
max_side: 256,
},
false,
)}
previewURL={member.client.generateFileURL(
member.avatar ?? undefined,
{ max_side: 256 },
true,
)}
desaturateDefault
/>
</Column>
<Column grow>
<Category compact>Preview</Category>
<Preview>
<Message message={message} head />
</Preview>
</Column>
</Row>
</Column>
</Modal>
);
},
);

View File

@@ -25,6 +25,7 @@ import MFARecovery from "./components/MFARecovery";
import ModifyAccount from "./components/ModifyAccount";
import OutOfDate from "./components/OutOfDate";
import PendingFriendRequests from "./components/PendingFriendRequests";
import ServerIdentity from "./components/ServerIdentity";
import ShowToken from "./components/ShowToken";
import SignOutSessions from "./components/SignOutSessions";
import SignedOut from "./components/SignedOut";
@@ -211,6 +212,7 @@ export const modalController = new ModalControllerExtended({
modify_account: ModifyAccount,
out_of_date: OutOfDate,
pending_friend_requests: PendingFriendRequests,
server_identity: ServerIdentity,
show_token: ShowToken,
signed_out: SignedOut,
sign_out_sessions: SignOutSessions,

View File

@@ -1,4 +1,4 @@
import { API, Client, User } from "revolt.js";
import { API, Client, User, Member } from "revolt.js";
export type Modal = {
key?: string;
@@ -65,6 +65,10 @@ export type Modal = {
client: Client;
field: "username" | "email" | "password";
}
| {
type: "server_identity";
member: Member;
}
| {
type: "signed_out";
}

View File

@@ -11,6 +11,8 @@ import { IconButton, Preloader } from "@revoltchat/ui";
import { determineFileSize } from "../../lib/fileSize";
import { useApplicationState } from "../../mobx/State";
import { useIntermediate } from "../intermediate/Intermediate";
import { modalController } from "../modals";
import { AppContext } from "./RevoltClient";
@@ -113,7 +115,7 @@ export function grabFiles(
export function FileUploader(props: Props) {
const { fileType, maxFileSize, remove } = props;
const { openScreen } = useIntermediate();
const client = useContext(AppContext);
const client = useApplicationState().client!;
const [uploading, setUploading] = useState(false);