diff --git a/package.json b/package.json index a22ed1cf..3f6fda66 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "@hcaptcha/react-hcaptcha": "^0.3.6", "@insertish/vite-plugin-babel-macros": "^1.0.5", "@preact/preset-vite": "^2.0.0", - "@revoltchat/ui": "1.0.58", + "@revoltchat/ui": "1.0.61", "@rollup/plugin-replace": "^2.4.2", "@styled-icons/boxicons-logos": "^10.38.0", "@styled-icons/boxicons-regular": "^10.38.0", diff --git a/src/components/navigation/left/HomeSidebar.tsx b/src/components/navigation/left/HomeSidebar.tsx index 9dcfb8e9..b1f1d659 100644 --- a/src/components/navigation/left/HomeSidebar.tsx +++ b/src/components/navigation/left/HomeSidebar.tsx @@ -25,6 +25,7 @@ import { useIntermediate } from "../../../context/intermediate/Intermediate"; import placeholderSVG from "../items/placeholder.svg"; import { useClient } from "../../../controllers/client/ClientController"; +import { modalController } from "../../../controllers/modals/ModalController"; import { GenericSidebarBase, GenericSidebarList } from "../SidebarBase"; import ButtonItem, { ChannelButton } from "../items/ButtonItem"; import ConnectionStatus from "../items/ConnectionStatus"; @@ -131,8 +132,7 @@ export default observer(() => { - openScreen({ - id: "special_input", + modalController.push({ type: "create_group", }) }> diff --git a/src/components/navigation/left/ServerListSidebar.tsx b/src/components/navigation/left/ServerListSidebar.tsx index ed703a31..b9189b23 100644 --- a/src/components/navigation/left/ServerListSidebar.tsx +++ b/src/components/navigation/left/ServerListSidebar.tsx @@ -7,9 +7,8 @@ import { ServerList } from "@revoltchat/ui"; import { useApplicationState } from "../../../mobx/State"; -import { useIntermediate } from "../../../context/intermediate/Intermediate"; - import { useClient } from "../../../controllers/client/ClientController"; +import { modalController } from "../../../controllers/modals/ModalController"; /** * Server list sidebar shim component @@ -17,13 +16,11 @@ import { useClient } from "../../../controllers/client/ClientController"; export default observer(() => { const client = useClient(); const state = useApplicationState(); - const { openScreen } = useIntermediate(); const { server: server_id } = useParams<{ server?: string }>(); const createServer = useCallback( () => - openScreen({ - id: "special_input", + modalController.push({ type: "create_server", }), [], diff --git a/src/components/settings/appearance/ChatOptions.tsx b/src/components/settings/appearance/ChatOptions.tsx index a6a0aa11..df947383 100644 --- a/src/components/settings/appearance/ChatOptions.tsx +++ b/src/components/settings/appearance/ChatOptions.tsx @@ -8,7 +8,21 @@ import { useApplicationState } from "../../../mobx/State"; import { FONTS, Fonts, FONT_KEYS } from "../../../context/Theme"; -import { ShimDisplayEmoji } from "../appearance_legacy/Shims"; +import { EmojiSelector } from "./legacy/EmojiSelector"; + +/** + * ! LEGACY + * Component providing a way to change emoji pack. + */ +export const ShimDisplayEmoji = observer(() => { + const settings = useApplicationState().settings; + return ( + settings.set("appearance:emoji", v)} + /> + ); +}); export default observer(() => { const settings = useApplicationState().settings; diff --git a/src/context/intermediate/modals/Input.tsx b/src/context/intermediate/modals/Input.tsx index d4e20b69..f912b861 100644 --- a/src/context/intermediate/modals/Input.tsx +++ b/src/context/intermediate/modals/Input.tsx @@ -93,96 +93,6 @@ export function SpecialInputModal(props: SpecialProps) { const { onClose } = props; switch (props.type) { - case "create_group": { - return ( - } - field={} - callback={async (name) => { - const group = await client.channels.createGroup({ - name, - users: [], - }); - - history.push(`/channel/${group._id}`); - }} - /> - ); - } - case "create_server": { - return ( - } - field={} - description={ - - By creating this server, you agree to the{" "} - - Acceptable Use Policy. - - - } - callback={async (name) => { - const server = await client.servers.createServer({ - name, - }); - - history.push(`/server/${server._id}`); - }} - /> - ); - } - case "create_role": { - return ( - - } - field={} - callback={async (name) => { - const role = await props.server.createRole(name); - props.callback(role.id); - }} - /> - ); - } - case "set_custom_status": { - return ( - } - field={} - defaultValue={client.user?.status?.text ?? undefined} - callback={(text) => - client.users.edit({ - status: { - ...client.user?.status, - text: text.trim().length > 0 ? text : undefined, - }, - }) - } - /> - ); - } - case "add_friend": { - return ( - - client.api - .post(`/users/friend`, { username }) - .then(undefined) - } - /> - ); - } default: return null; } diff --git a/src/context/revoltjs/util.tsx b/src/context/revoltjs/util.tsx index e82713a4..2523ba0c 100644 --- a/src/context/revoltjs/util.tsx +++ b/src/context/revoltjs/util.tsx @@ -27,6 +27,11 @@ export function takeError(error: any): string { return "UnknownError"; } +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function mapError(error: any): never { + throw takeError(error); +} + export function getChannelName( channel: Channel, prefixType?: boolean, diff --git a/src/controllers/modals/ModalController.tsx b/src/controllers/modals/ModalController.tsx index a8169d0e..340e1021 100644 --- a/src/controllers/modals/ModalController.tsx +++ b/src/controllers/modals/ModalController.tsx @@ -16,9 +16,14 @@ import { getApplicationState } from "../../mobx/State"; import { history } from "../../context/history"; import { __thisIsAHack } from "../../context/intermediate/Intermediate"; +import AddFriend from "./components/AddFriend"; import Changelog from "./components/Changelog"; import ChannelInfo from "./components/ChannelInfo"; import Clipboard from "./components/Clipboard"; +import CreateGroup from "./components/CreateGroup"; +import CreateRole from "./components/CreateRole"; +import CreateServer from "./components/CreateServer"; +import CustomStatus from "./components/CustomStatus"; import Error from "./components/Error"; import ImageViewer from "./components/ImageViewer"; import LinkWarning from "./components/LinkWarning"; @@ -222,10 +227,15 @@ class ModalControllerExtended extends ModalController { } export const modalController = new ModalControllerExtended({ + add_friend: AddFriend, changelog: Changelog, channel_info: ChannelInfo, clipboard: Clipboard, + create_group: CreateGroup, + create_role: CreateRole, + create_server: CreateServer, create_bot: CreateBotModal, + custom_status: CustomStatus, error: Error, image_viewer: ImageViewer, link_warning: LinkWarning, diff --git a/src/controllers/modals/components/AddFriend.tsx b/src/controllers/modals/components/AddFriend.tsx new file mode 100644 index 00000000..e239012b --- /dev/null +++ b/src/controllers/modals/components/AddFriend.tsx @@ -0,0 +1,31 @@ +import { ModalForm } from "@revoltchat/ui"; + +import { noop } from "../../../lib/js"; + +import { useClient } from "../../client/ClientController"; +import { ModalProps } from "../types"; + +/** + * Add friend modal + */ +export default function AddFriend({ ...props }: ModalProps<"add_friend">) { + const client = useClient(); + + return ( + + client.api.post(`/users/friend`, { username }).then(noop) + } + /> + ); +} diff --git a/src/controllers/modals/components/CreateGroup.tsx b/src/controllers/modals/components/CreateGroup.tsx new file mode 100644 index 00000000..797e23e0 --- /dev/null +++ b/src/controllers/modals/components/CreateGroup.tsx @@ -0,0 +1,45 @@ +import { useHistory } from "react-router-dom"; + +import { Text } from "preact-i18n"; + +import { ModalForm } from "@revoltchat/ui"; + +import { mapError } from "../../../context/revoltjs/util"; + +import { useClient } from "../../client/ClientController"; +import { ModalProps } from "../types"; + +/** + * Group creation modal + */ +export default function CreateGroup({ ...props }: ModalProps<"create_group">) { + const history = useHistory(); + const client = useClient(); + + return ( + } + schema={{ + name: "text", + }} + data={{ + name: { + field: ( + + ) as React.ReactChild, + }, + }} + callback={async ({ name }) => { + const group = await client.channels + .createGroup({ + name, + users: [], + }) + .catch(mapError); + + history.push(`/channel/${group._id}`); + }} + /> + ); +} diff --git a/src/controllers/modals/components/CreateRole.tsx b/src/controllers/modals/components/CreateRole.tsx new file mode 100644 index 00000000..4ce5d038 --- /dev/null +++ b/src/controllers/modals/components/CreateRole.tsx @@ -0,0 +1,35 @@ +import { Text } from "preact-i18n"; + +import { ModalForm } from "@revoltchat/ui"; + +import { ModalProps } from "../types"; + +/** + * Role creation modal + */ +export default function CreateRole({ + server, + callback, + ...props +}: ModalProps<"create_role">) { + return ( + } + schema={{ + name: "text", + }} + data={{ + name: { + field: ( + + ) as React.ReactChild, + }, + }} + callback={async ({ name }) => { + const role = await server.createRole(name); + callback(role.id); + }} + /> + ); +} diff --git a/src/controllers/modals/components/CreateServer.tsx b/src/controllers/modals/components/CreateServer.tsx new file mode 100644 index 00000000..b6f6a374 --- /dev/null +++ b/src/controllers/modals/components/CreateServer.tsx @@ -0,0 +1,57 @@ +import { useHistory } from "react-router-dom"; + +import { Text } from "preact-i18n"; + +import { ModalForm } from "@revoltchat/ui"; + +import { mapError } from "../../../context/revoltjs/util"; + +import { useClient } from "../../client/ClientController"; +import { ModalProps } from "../types"; + +/** + * Server creation modal + */ +export default function CreateServer({ + ...props +}: ModalProps<"create_server">) { + const history = useHistory(); + const client = useClient(); + + return ( + } + description={ + + By creating this server, you agree to the{" "} + + Acceptable Use Policy. + + + } + schema={{ + name: "text", + }} + data={{ + name: { + field: ( + + ) as React.ReactChild, + }, + }} + callback={async ({ name }) => { + const server = await client.servers + .createServer({ + name, + }) + .catch(mapError); + + history.push(`/server/${server._id}`); + }} + /> + ); +} diff --git a/src/controllers/modals/components/CustomStatus.tsx b/src/controllers/modals/components/CustomStatus.tsx new file mode 100644 index 00000000..7db3ddac --- /dev/null +++ b/src/controllers/modals/components/CustomStatus.tsx @@ -0,0 +1,43 @@ +import { Text } from "preact-i18n"; + +import { ModalForm } from "@revoltchat/ui"; + +import { useClient } from "../../client/ClientController"; +import { ModalProps } from "../types"; + +/** + * Custom status modal + */ +export default function CustomStatus({ + ...props +}: ModalProps<"custom_status">) { + const client = useClient(); + + return ( + } + schema={{ + text: "text", + }} + defaults={{ + text: client.user?.status?.text as string, + }} + data={{ + text: { + field: ( + + ) as React.ReactChild, + }, + }} + callback={({ text }) => + client.users.edit({ + status: { + ...client.user?.status, + text: text.trim().length > 0 ? text : undefined, + }, + }) + } + /> + ); +} diff --git a/src/controllers/modals/types.ts b/src/controllers/modals/types.ts index 2471b82c..5ffc5fef 100644 --- a/src/controllers/modals/types.ts +++ b/src/controllers/modals/types.ts @@ -3,6 +3,14 @@ import { API, Client, User, Member, Channel, Server } from "revolt.js"; export type Modal = { key?: string; } & ( + | { + type: + | "signed_out" + | "create_group" + | "create_server" + | "custom_status" + | "add_friend"; + } | ({ type: "mfa_flow"; } & ( @@ -69,9 +77,6 @@ export type Modal = { type: "server_identity"; member: Member; } - | { - type: "signed_out"; - } | { type: "channel_info"; channel: Channel; @@ -107,6 +112,11 @@ export type Modal = { loginAfterSuccess?: true, ) => Promise; } + | { + type: "create_role"; + server: Server; + callback: (id: string) => void; + } ); export type ModalProps = Modal & { type: T } & { diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx index 6c1d1ddc..67fc3018 100644 --- a/src/lib/ContextMenus.tsx +++ b/src/lib/ContextMenus.tsx @@ -368,9 +368,8 @@ export default function ContextMenus() { break; case "set_status": - openScreen({ - id: "special_input", - type: "set_custom_status", + modalController.push({ + type: "custom_status", }); break; diff --git a/src/pages/friends/Friends.tsx b/src/pages/friends/Friends.tsx index 3b6fa516..a479b46b 100644 --- a/src/pages/friends/Friends.tsx +++ b/src/pages/friends/Friends.tsx @@ -85,8 +85,7 @@ export default observer(() => { - openScreen({ - id: "special_input", + modalController.push({ type: "create_group", }) }> @@ -96,8 +95,7 @@ export default observer(() => { - openScreen({ - id: "special_input", + modalController.push({ type: "add_friend", }) }> diff --git a/src/pages/home/Home.tsx b/src/pages/home/Home.tsx index 9690af9d..67784147 100644 --- a/src/pages/home/Home.tsx +++ b/src/pages/home/Home.tsx @@ -29,6 +29,7 @@ import wideSVG from "/assets/wide.svg"; import { PageHeader } from "../../components/ui/Header"; import { useClient } from "../../controllers/client/ClientController"; +import { modalController } from "../../controllers/modals/ModalController"; const Overlay = styled.div` display: grid; @@ -98,8 +99,7 @@ export default observer(() => { - openScreen({ - id: "special_input", + modalController.push({ type: "create_group", }) }> diff --git a/src/pages/settings/Settings.tsx b/src/pages/settings/Settings.tsx index cc697ccc..022f0c85 100644 --- a/src/pages/settings/Settings.tsx +++ b/src/pages/settings/Settings.tsx @@ -347,9 +347,8 @@ export default observer(() => { - openScreen({ - id: "special_input", - type: "set_custom_status", + modalController.push({ + type: "custom_status", }) }> Change your status... diff --git a/src/pages/settings/server/Roles.tsx b/src/pages/settings/server/Roles.tsx index aa70f81f..de43c626 100644 --- a/src/pages/settings/server/Roles.tsx +++ b/src/pages/settings/server/Roles.tsx @@ -16,10 +16,9 @@ import { Category, } from "@revoltchat/ui"; -import { useIntermediate } from "../../../context/intermediate/Intermediate"; - import { PermissionList } from "../../../components/settings/roles/PermissionList"; import { RoleOrDefault } from "../../../components/settings/roles/RoleSelection"; +import { modalController } from "../../../controllers/modals/ModalController"; interface Props { server: Server; @@ -54,18 +53,14 @@ export const Roles = observer(({ server }: Props) => { // Consolidate all permissions that we can change right now. const currentRoles = useRoles(server); - // Pull in modal context. - const { openScreen } = useIntermediate(); - return ( - openScreen({ - id: "special_input", + modalController.push({ type: "create_role", - server: server as any, + server, callback, }) } diff --git a/yarn.lock b/yarn.lock index 130f5d85..b674b8fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2231,9 +2231,9 @@ __metadata: languageName: node linkType: hard -"@revoltchat/ui@npm:1.0.58": - version: 1.0.58 - resolution: "@revoltchat/ui@npm:1.0.58" +"@revoltchat/ui@npm:1.0.61": + version: 1.0.61 + resolution: "@revoltchat/ui@npm:1.0.61" dependencies: "@styled-icons/boxicons-logos": ^10.38.0 "@styled-icons/boxicons-regular": ^10.38.0 @@ -2247,7 +2247,7 @@ __metadata: react-virtuoso: ^2.12.0 peerDependencies: revolt.js: "*" - checksum: 1ebdb3963c77fbad11427963e27f1be1beb480e80360a59f06a3a2fd2d3f5e335ff33fbb8bf99f533549696848ae1d1db5072ff4d45e98d25c9b1b372f25d795 + checksum: 678584f84cb3d43307507058eb434507cb1d201455f9da6618eb1731c6439240ddc16601dc636b5790a83393884770bf4e8fee75d235871f65ba5abcd8f685ac languageName: node linkType: hard @@ -3554,7 +3554,7 @@ __metadata: "@hcaptcha/react-hcaptcha": ^0.3.6 "@insertish/vite-plugin-babel-macros": ^1.0.5 "@preact/preset-vite": ^2.0.0 - "@revoltchat/ui": 1.0.58 + "@revoltchat/ui": 1.0.61 "@rollup/plugin-replace": ^2.4.2 "@styled-icons/boxicons-logos": ^10.38.0 "@styled-icons/boxicons-regular": ^10.38.0