From f9c6f5cd9d320b3c3156371f63009b9e31ab51b3 Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Tue, 5 Jul 2022 21:13:42 +0100 Subject: [PATCH] chore: delete intermediate --- src/components/common/messaging/Message.tsx | 3 - .../messaging/bars/MessageOverlayBar.tsx | 11 +- .../common/messaging/embed/Embed.tsx | 9 +- src/components/common/user/UserHeader.tsx | 9 +- src/components/markdown/Renderer.tsx | 66 +-- .../navigation/items/ButtonItem.tsx | 4 - .../navigation/left/HomeSidebar.tsx | 3 - .../settings/appearance/legacy/ThemeTools.tsx | 20 +- src/context/index.tsx | 7 +- src/context/intermediate/Intermediate.tsx | 219 ------- src/context/intermediate/Modals.tsx | 25 - src/context/intermediate/Popovers.tsx | 26 - src/context/intermediate/modals/Input.tsx | 99 ---- .../intermediate/modals/Prompt.module.scss | 18 - src/context/intermediate/modals/Prompt.tsx | 561 ------------------ .../popovers/UserPicker.module.scss | 5 - src/context/revoltjs/FileUploads.tsx | 4 +- src/controllers/client/Session.tsx | 2 - src/controllers/modals/ModalRenderer.tsx | 22 +- .../modals/components/ImportTheme.tsx | 32 + src/controllers/modals/types.ts | 3 + src/lib/ContextMenus.tsx | 18 +- src/pages/RevoltApp.tsx | 3 - src/pages/channels/actions/HeaderActions.tsx | 3 - src/pages/channels/messaging/MessageArea.tsx | 8 +- .../channels/messaging/MessageEditor.tsx | 10 +- src/pages/channels/voice/VoiceHeader.tsx | 4 - src/pages/discover/Discover.tsx | 6 +- src/pages/friends/Friend.tsx | 3 - src/pages/friends/Friends.tsx | 4 - src/pages/home/Home.tsx | 3 - src/pages/settings/ServerSettings.tsx | 3 - src/pages/settings/Settings.tsx | 3 - src/pages/settings/panes/MyBots.tsx | 10 +- src/pages/settings/server/Categories.tsx | 7 +- 35 files changed, 129 insertions(+), 1104 deletions(-) delete mode 100644 src/context/intermediate/Intermediate.tsx delete mode 100644 src/context/intermediate/Modals.tsx delete mode 100644 src/context/intermediate/Popovers.tsx delete mode 100644 src/context/intermediate/modals/Input.tsx delete mode 100644 src/context/intermediate/modals/Prompt.module.scss delete mode 100644 src/context/intermediate/modals/Prompt.tsx delete mode 100644 src/context/intermediate/popovers/UserPicker.module.scss create mode 100644 src/controllers/modals/components/ImportTheme.tsx diff --git a/src/components/common/messaging/Message.tsx b/src/components/common/messaging/Message.tsx index 8f684141..e7521660 100644 --- a/src/components/common/messaging/Message.tsx +++ b/src/components/common/messaging/Message.tsx @@ -13,7 +13,6 @@ import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice"; import { QueuedMessage } from "../../../mobx/stores/MessageQueue"; import { I18nError } from "../../../context/Locale"; -import { useIntermediate } from "../../../context/intermediate/Intermediate"; import { modalController } from "../../../controllers/modals/ModalController"; import Markdown from "../../markdown/Markdown"; @@ -55,8 +54,6 @@ const Message = observer( const client = message.client; const user = message.author; - const { openScreen } = useIntermediate(); - const content = message.content; const head = preferHead || (message.reply_ids && message.reply_ids.length > 0); diff --git a/src/components/common/messaging/bars/MessageOverlayBar.tsx b/src/components/common/messaging/bars/MessageOverlayBar.tsx index 9104593f..8f38e655 100644 --- a/src/components/common/messaging/bars/MessageOverlayBar.tsx +++ b/src/components/common/messaging/bars/MessageOverlayBar.tsx @@ -19,12 +19,6 @@ import { getRenderer } from "../../../../lib/renderer/Singleton"; import { QueuedMessage } from "../../../../mobx/stores/MessageQueue"; -import { - Screen, - useIntermediate, -} from "../../../../context/intermediate/Intermediate"; - -import { useClient } from "../../../../controllers/client/ClientController"; import { modalController } from "../../../../controllers/modals/ModalController"; import Tooltip from "../../../common/Tooltip"; @@ -89,7 +83,6 @@ const Divider = styled.div` export const MessageOverlayBar = observer(({ message, queued }: Props) => { const client = message.client; - const { openScreen, writeClipboard } = useIntermediate(); const isAuthor = message.author_id === client.user!._id; const [copied, setCopied] = useState<"link" | "id">(null!); @@ -189,7 +182,7 @@ export const MessageOverlayBar = observer(({ message, queued }: Props) => { { setCopied("link"); - writeClipboard(message.url); + modalController.writeText(message.url); }}> @@ -200,7 +193,7 @@ export const MessageOverlayBar = observer(({ message, queued }: Props) => { { setCopied("id"); - writeClipboard(message._id); + modalController.writeText(message._id); }}> diff --git a/src/components/common/messaging/embed/Embed.tsx b/src/components/common/messaging/embed/Embed.tsx index 822f30b2..3d04c44f 100644 --- a/src/components/common/messaging/embed/Embed.tsx +++ b/src/components/common/messaging/embed/Embed.tsx @@ -4,8 +4,6 @@ import styles from "./Embed.module.scss"; import classNames from "classnames"; import { useContext } from "preact/hooks"; -import { useIntermediate } from "../../../../context/intermediate/Intermediate"; - import { useClient } from "../../../../controllers/client/ClientController"; import { modalController } from "../../../../controllers/modals/ModalController"; import { MessageAreaWidthContext } from "../../../../pages/channels/messaging/MessageArea"; @@ -25,7 +23,6 @@ const MAX_PREVIEW_SIZE = 150; export default function Embed({ embed }: Props) { const client = useClient(); - const { openLink } = useIntermediate(); const maxWidth = Math.min( useContext(MessageAreaWidthContext) - CONTAINER_PADDING, MAX_EMBED_WIDTH, @@ -144,7 +141,7 @@ export default function Embed({ embed }: Props) { (ev.button === 0 || ev.button === 1) && - openLink(embed.url!) + modalController.openLink(embed.url!) } className={styles.title}> {embed.title} @@ -195,7 +192,9 @@ export default function Embed({ embed }: Props) { onClick={() => modalController.push({ type: "image_viewer", embed }) } - onMouseDown={(ev) => ev.button === 1 && openLink(embed.url)} + onMouseDown={(ev) => + ev.button === 1 && modalController.openLink(embed.url) + } /> ); } diff --git a/src/components/common/user/UserHeader.tsx b/src/components/common/user/UserHeader.tsx index 0ab85bfd..1c442799 100644 --- a/src/components/common/user/UserHeader.tsx +++ b/src/components/common/user/UserHeader.tsx @@ -11,8 +11,7 @@ import { Header, IconButton } from "@revoltchat/ui"; import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice"; -import { useIntermediate } from "../../../context/intermediate/Intermediate"; - +import { modalController } from "../../../controllers/modals/ModalController"; import Tooltip from "../Tooltip"; import UserStatus from "./UserStatus"; @@ -48,8 +47,6 @@ interface Props { } export default observer(({ user }: Props) => { - const { writeClipboard } = useIntermediate(); - return (
@@ -57,7 +54,9 @@ export default observer(({ user }: Props) => { }> writeClipboard(user.username)}> + onClick={() => + modalController.writeText(user.username) + }> @{user.username} diff --git a/src/components/markdown/Renderer.tsx b/src/components/markdown/Renderer.tsx index bcce42b8..73eaedd3 100644 --- a/src/components/markdown/Renderer.tsx +++ b/src/components/markdown/Renderer.tsx @@ -14,10 +14,10 @@ import { internalEmit } from "../../lib/eventEmitter"; import { determineLink } from "../../lib/links"; import { dayjs } from "../../context/Locale"; -import { useIntermediate } from "../../context/intermediate/Intermediate"; import { emojiDictionary } from "../../assets/emojis"; import { useClient } from "../../controllers/client/ClientController"; +import { modalController } from "../../controllers/modals/ModalController"; import { generateEmoji } from "../common/Emoji"; import { MarkdownProps } from "./Markdown"; import Prism from "./prism"; @@ -119,7 +119,6 @@ const RE_TIME = //g; export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) { const client = useClient(); - const { openLink } = useIntermediate(); if (typeof content === "undefined") return null; if (!content || content.length === 0) return null; @@ -191,43 +190,40 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) { } }, []); - const handleLink = useCallback( - (ev: MouseEvent) => { - if (ev.currentTarget) { - const element = ev.currentTarget as HTMLAnchorElement; + const handleLink = useCallback((ev: MouseEvent) => { + if (ev.currentTarget) { + const element = ev.currentTarget as HTMLAnchorElement; - if (ev.shiftKey) { - switch (element.dataset.type) { - case "mention": { - internalEmit( - "MessageBox", - "append", - `<@${element.dataset.mentionId}>`, - "mention", - ); - ev.preventDefault(); - return; - } - case "channel_mention": { - internalEmit( - "MessageBox", - "append", - `<#${element.dataset.mentionId}>`, - "channel_mention", - ); - ev.preventDefault(); - return; - } + if (ev.shiftKey) { + switch (element.dataset.type) { + case "mention": { + internalEmit( + "MessageBox", + "append", + `<@${element.dataset.mentionId}>`, + "mention", + ); + ev.preventDefault(); + return; + } + case "channel_mention": { + internalEmit( + "MessageBox", + "append", + `<#${element.dataset.mentionId}>`, + "channel_mention", + ); + ev.preventDefault(); + return; } } - - if (openLink(element.href)) { - ev.preventDefault(); - } } - }, - [openLink], - ); + + if (modalController.openLink(element.href)) { + ev.preventDefault(); + } + } + }, []); return ( { channel, ...divProps } = props; - const { openScreen } = useIntermediate(); return (
{ return ; } - const { openScreen } = useIntermediate(); const alerting = alert && !muted && !active; return ( diff --git a/src/components/navigation/left/HomeSidebar.tsx b/src/components/navigation/left/HomeSidebar.tsx index b1f1d659..e61439f9 100644 --- a/src/components/navigation/left/HomeSidebar.tsx +++ b/src/components/navigation/left/HomeSidebar.tsx @@ -20,8 +20,6 @@ import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice"; import { useApplicationState } from "../../../mobx/State"; -import { useIntermediate } from "../../../context/intermediate/Intermediate"; - import placeholderSVG from "../items/placeholder.svg"; import { useClient } from "../../../controllers/client/ClientController"; @@ -50,7 +48,6 @@ export default observer(() => { const client = useClient(); const state = useApplicationState(); const { channel: channel_id } = useParams<{ channel: string }>(); - const { openScreen } = useIntermediate(); const channels = [...client.channels.values()].filter( (x) => diff --git a/src/components/settings/appearance/legacy/ThemeTools.tsx b/src/components/settings/appearance/legacy/ThemeTools.tsx index bd3a3f5b..db5edff0 100644 --- a/src/components/settings/appearance/legacy/ThemeTools.tsx +++ b/src/components/settings/appearance/legacy/ThemeTools.tsx @@ -7,8 +7,7 @@ import { Button } from "@revoltchat/ui"; import { useApplicationState } from "../../../../mobx/State"; -import { useIntermediate } from "../../../../context/intermediate/Intermediate"; - +import { modalController } from "../../../../controllers/modals/ModalController"; import Tooltip from "../../../common/Tooltip"; const Actions = styled.div` @@ -38,7 +37,6 @@ const Actions = styled.div` `; export default function ThemeTools() { - const { writeClipboard, openScreen } = useIntermediate(); const theme = useApplicationState().settings.theme; return ( @@ -56,7 +54,9 @@ export default function ThemeTools() {
writeClipboard(JSON.stringify(theme))}> + onClick={() => + modalController.writeText(JSON.stringify(theme)) + }> }> {" "} {JSON.stringify(theme)} @@ -72,16 +72,8 @@ export default function ThemeTools() { const text = await navigator.clipboard.readText(); theme.hydrate(JSON.parse(text)); } catch (err) { - openScreen({ - id: "_input", - question: ( - - ), - field: ( - - ), - callback: async (text) => - theme.hydrate(JSON.parse(text)), + modalController.push({ + type: "import_theme", }); } }}> diff --git a/src/context/index.tsx b/src/context/index.tsx index 51b0564f..86464484 100644 --- a/src/context/index.tsx +++ b/src/context/index.tsx @@ -13,7 +13,6 @@ import ModalRenderer from "../controllers/modals/ModalRenderer"; import Locale from "./Locale"; import Theme from "./Theme"; import { history } from "./history"; -import Intermediate from "./intermediate/Intermediate"; const uiContext = { Link, @@ -39,10 +38,8 @@ export default function Context({ children }: { children: Children }) { - - {children} - - + <>{children} + diff --git a/src/context/intermediate/Intermediate.tsx b/src/context/intermediate/Intermediate.tsx deleted file mode 100644 index e67ca0ae..00000000 --- a/src/context/intermediate/Intermediate.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import { Prompt } from "react-router"; -import { useHistory } from "react-router-dom"; -import { API, Channel, Message, Server, User } from "revolt.js"; - -import { createContext } from "preact"; -import { - StateUpdater, - useContext, - useEffect, - useMemo, - useState, -} from "preact/hooks"; - -import type { Action } from "@revoltchat/ui/esm/components/design/atoms/display/Modal"; - -import { internalSubscribe } from "../../lib/eventEmitter"; -import { determineLink } from "../../lib/links"; - -import { useApplicationState } from "../../mobx/State"; - -import { modalController } from "../../controllers/modals/ModalController"; -import Modals from "./Modals"; - -export type Screen = - | { id: "none" } - - // Modals - | { id: "signed_out" } - | { id: "error"; error: string } - | { id: "clipboard"; text: string } - | { id: "token_reveal"; token: string; username: string } - | { id: "external_link_prompt"; link: string } - | { id: "sessions"; confirm: () => void } - | { - id: "_prompt"; - question: Children; - content?: Children; - actions: Action[]; - } - | ({ id: "special_prompt" } & ( - | { type: "leave_group"; target: Channel } - | { type: "close_dm"; target: Channel } - | { type: "leave_server"; target: Server } - | { type: "delete_server"; target: Server } - | { type: "delete_channel"; target: Channel } - | { - type: "delete_bot"; - target: string; - name: string; - cb?: () => void; - } - | { type: "delete_message"; target: Message } - | { - type: "create_invite"; - target: Channel; - } - | { type: "kick_member"; target: Server; user: User } - | { type: "ban_member"; target: Server; user: User } - | { type: "unfriend_user"; target: User } - | { type: "block_user"; target: User } - | { - type: "create_channel"; - target: Server; - cb?: ( - channel: Channel & { - channel_type: "TextChannel" | "VoiceChannel"; - }, - ) => void; - } - | { type: "create_category"; target: Server } - )) - | ({ id: "special_input" } & ( - | { - type: - | "create_group" - | "create_server" - | "set_custom_status" - | "add_friend"; - } - | { - type: "create_role"; - server: Server; - callback: (id: string) => void; - } - )) - | { - id: "_input"; - question: Children; - field: Children; - defaultValue?: string; - callback: (value: string) => Promise; - } - | { - id: "onboarding"; - callback: ( - username: string, - loginAfterSuccess?: true, - ) => Promise; - } - - // Pop-overs - | { id: "profile"; user_id: string } - | { - id: "user_picker"; - omit?: string[]; - callback: (users: string[]) => Promise; - } - | { id: "image_viewer"; attachment?: API.File; embed?: API.Image } - | { id: "channel_info"; channel: Channel } - | { id: "pending_requests"; users: User[] } - | { id: "modify_account"; field: "username" | "email" | "password" } - | { id: "create_bot"; onCreate: (bot: API.Bot) => void } - | { - id: "server_identity"; - server: Server; - }; - -export const IntermediateContext = createContext({ - screen: { id: "none" }, - focusTaken: false, -}); - -export const IntermediateActionsContext = createContext<{ - openLink: (href?: string, trusted?: boolean) => boolean; - openScreen: (screen: Screen) => void; - writeClipboard: (text: string) => void; -}>({ - openLink: null!, - openScreen: null!, - writeClipboard: null!, -}); - -interface Props { - children: Children; -} - -export let __thisIsAHack: StateUpdater; - -export default function Intermediate(props: Props) { - const [screen, openScreen] = useState({ id: "none" }); - __thisIsAHack = openScreen; - const history = useHistory(); - - const value = { - screen, - focusTaken: screen.id !== "none", - }; - - const actions = useMemo(() => { - return { - openLink: (href?: string, trusted?: boolean) => { - return modalController.openLink(href, trusted); - }, - openScreen: (screen: Screen) => openScreen(screen), - writeClipboard: (a: string) => modalController.writeText(a), - }; - // eslint-disable-next-line - }, []); - - useEffect(() => { - const openProfile = (user_id: string) => - modalController.push({ type: "user_profile", user_id }); - const navigate = (path: string) => history.push(path); - - const subs = [ - internalSubscribe( - "Intermediate", - "openProfile", - openProfile as (...args: unknown[]) => void, - ), - internalSubscribe( - "Intermediate", - "navigate", - navigate as (...args: unknown[]) => void, - ), - ]; - - return () => subs.map((unsub) => unsub()); - }, [history]); - - return ( - - - {screen.id !== "onboarding" && props.children} - - { - if (action === "POP") { - openScreen({ id: "none" }); - setTimeout(() => history.push(history.location), 0); - - return false; - } - - return true; - }} - /> - - - ); -} - -export const useIntermediate = () => useContext(IntermediateActionsContext); diff --git a/src/context/intermediate/Modals.tsx b/src/context/intermediate/Modals.tsx deleted file mode 100644 index 48e18245..00000000 --- a/src/context/intermediate/Modals.tsx +++ /dev/null @@ -1,25 +0,0 @@ -//import { isModalClosing } from "../../components/ui/Modal"; -import { Screen } from "./Intermediate"; -import { InputModal } from "./modals/Input"; -import { PromptModal } from "./modals/Prompt"; - -export interface Props { - screen: Screen; - openScreen: (screen: Screen) => void; -} - -export default function Modals({ screen, openScreen }: Props) { - const onClose = () => - //isModalClosing || screen.id === "onboarding" - openScreen({ id: "none" }); - // : internalEmit("Modal", "close"); - - switch (screen.id) { - case "_prompt": - return ; - case "_input": - return ; - } - - return null; -} diff --git a/src/context/intermediate/Popovers.tsx b/src/context/intermediate/Popovers.tsx deleted file mode 100644 index 08386727..00000000 --- a/src/context/intermediate/Popovers.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { useContext } from "preact/hooks"; - -import { IntermediateContext, useIntermediate } from "./Intermediate"; -import { SpecialInputModal } from "./modals/Input"; -import { SpecialPromptModal } from "./modals/Prompt"; - -export default function Popovers() { - const { screen } = useContext(IntermediateContext); - const { openScreen } = useIntermediate(); - - const onClose = () => - //isModalClosing - openScreen({ id: "none" }); - //: internalEmit("Modal", "close"); - - switch (screen.id) { - case "special_prompt": - // @ts-expect-error someone figure this out :) - return ; - case "special_input": - // @ts-expect-error someone figure this out :) - return ; - } - - return null; -} diff --git a/src/context/intermediate/modals/Input.tsx b/src/context/intermediate/modals/Input.tsx deleted file mode 100644 index f912b861..00000000 --- a/src/context/intermediate/modals/Input.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { useHistory } from "react-router"; -import { Server } from "revolt.js"; - -import { Text } from "preact-i18n"; -import { useContext, useState } from "preact/hooks"; - -import { Category, InputBox, Modal } from "@revoltchat/ui"; - -import { useClient } from "../../../controllers/client/ClientController"; -import { I18nError } from "../../Locale"; -import { takeError } from "../../revoltjs/util"; - -interface Props { - onClose: () => void; - question: Children; - field?: Children; - description?: Children; - defaultValue?: string; - callback: (value: string) => Promise; -} - -export function InputModal({ - onClose, - question, - field, - description, - defaultValue, - callback, -}: Props) { - const [processing, setProcessing] = useState(false); - const [value, setValue] = useState(defaultValue ?? ""); - const [error, setError] = useState(undefined); - - return ( - , - onClick: () => { - setProcessing(true); - callback(value) - .then(onClose) - .catch((err) => { - setError(takeError(err)); - setProcessing(false); - }); - }, - }, - { - children: , - onClick: onClose, - }, - ]} - onClose={onClose}> - {field ? ( - - {field} - - ) : ( - error && ( - - - - ) - )} - setValue(e.currentTarget.value)} - /> - - ); -} - -type SpecialProps = { onClose: () => void } & ( - | { - type: - | "create_group" - | "create_server" - | "set_custom_status" - | "add_friend"; - } - | { type: "create_role"; server: Server; callback: (id: string) => void } -); - -export function SpecialInputModal(props: SpecialProps) { - const history = useHistory(); - const client = useClient(); - - const { onClose } = props; - switch (props.type) { - default: - return null; - } -} diff --git a/src/context/intermediate/modals/Prompt.module.scss b/src/context/intermediate/modals/Prompt.module.scss deleted file mode 100644 index 9a930faf..00000000 --- a/src/context/intermediate/modals/Prompt.module.scss +++ /dev/null @@ -1,18 +0,0 @@ -.invite { - display: flex; - flex-direction: column; - - code { - padding: 1em; - user-select: all; - font-size: 1.4em; - text-align: center; - font-family: var(--monospace-font); - } -} - -.column { - display: flex; - align-items: center; - flex-direction: column; -} diff --git a/src/context/intermediate/modals/Prompt.tsx b/src/context/intermediate/modals/Prompt.tsx deleted file mode 100644 index a6add7aa..00000000 --- a/src/context/intermediate/modals/Prompt.tsx +++ /dev/null @@ -1,561 +0,0 @@ -import { observer } from "mobx-react-lite"; -import { useHistory } from "react-router-dom"; -import { Channel, Message as MessageI, Server, User } from "revolt.js"; -import { ulid } from "ulid"; - -import styles from "./Prompt.module.scss"; -import { Text } from "preact-i18n"; -import { useEffect, useState } from "preact/hooks"; - -import { Category, Modal, InputBox, Radio } from "@revoltchat/ui"; -import type { Action } from "@revoltchat/ui/esm/components/design/atoms/display/Modal"; - -import { TextReact } from "../../../lib/i18n"; - -import Message from "../../../components/common/messaging/Message"; -import UserIcon from "../../../components/common/user/UserIcon"; -import { useClient } from "../../../controllers/client/ClientController"; -import { I18nError } from "../../Locale"; -import { takeError } from "../../revoltjs/util"; -import { useIntermediate } from "../Intermediate"; - -interface Props { - onClose: () => void; - question: Children; - description?: Children; - content?: Children; - disabled?: boolean; - actions: Action[]; - error?: string; -} - -export function PromptModal({ - onClose, - question, - description, - content, - actions, - disabled, - error, -}: Props) { - return ( - - {error && ( - - - - )} - {content} - - ); -} - -type SpecialProps = { onClose: () => void } & ( - | { type: "leave_group"; target: Channel } - | { type: "close_dm"; target: Channel } - | { type: "delete_channel"; target: Channel } - | { - type: "create_invite"; - target: Channel; - } - - | { type: "leave_server"; target: Server } - | { type: "delete_server"; target: Server } - - | { type: "delete_bot"; target: string; name: string; cb?: () => void } - - | { type: "delete_message"; target: MessageI } - - | { type: "kick_member"; target: Server; user: User } - | { type: "ban_member"; target: Server; user: User } - - | { type: "unfriend_user"; target: User } - | { type: "block_user"; target: User } - - | { - type: "create_channel"; - target: Server; - cb?: ( - channel: Channel & { - channel_type: "TextChannel" | "VoiceChannel"; - }, - ) => void; - } - - | { type: "create_category"; target: Server } -); - -export const SpecialPromptModal = observer((props: SpecialProps) => { - const client = useClient(); - const history = useHistory(); - const [processing, setProcessing] = useState(false); - const [error, setError] = useState(undefined); - - const { onClose } = props; - switch (props.type) { - case "leave_group": - case "close_dm": - case "leave_server": - case "delete_server": - case "delete_channel": - case "delete_bot": - case "unfriend_user": - case "block_user": { - const EVENTS = { - close_dm: ["confirm_close_dm", "close"], - delete_server: ["confirm_delete", "delete"], - delete_channel: ["confirm_delete", "delete"], - delete_bot: ["confirm_delete", "delete"], - leave_group: ["confirm_leave", "leave"], - leave_server: ["confirm_leave", "leave"], - unfriend_user: ["unfriend_user", "remove"], - block_user: ["block_user", "block"], - }; - - const event = EVENTS[props.type]; - let name; - switch (props.type) { - case "unfriend_user": - case "block_user": - name = props.target.username; - break; - case "close_dm": - name = props.target.recipient?.username; - break; - case "delete_bot": - name = props.name; - break; - default: - name = props.target.name; - } - - return ( - - } - description={ - {name} }} - /> - } - actions={[ - { - confirmation: true, - palette: "error", - children: ( - - ), - onClick: async () => { - setProcessing(true); - - try { - switch (props.type) { - case "unfriend_user": - await props.target.removeFriend(); - break; - case "block_user": - await props.target.blockUser(); - break; - case "leave_group": - case "close_dm": - case "delete_channel": - case "leave_server": - case "delete_server": - if (props.type != "delete_channel") - history.push("/"); - props.target.delete(); - break; - case "delete_bot": - client.bots.delete(props.target); - props.cb?.(); - break; - } - - return true; - } catch (err) { - setError(takeError(err)); - setProcessing(false); - return false; - } - }, - }, - { - children: ( - - ), - onClick: onClose, - }, - ]} - disabled={processing} - error={error} - /> - ); - } - case "delete_message": { - return ( - } - description={ - - } - actions={[ - { - confirmation: true, - palette: "error", - children: ( - - ), - onClick: async () => { - setProcessing(true); - - try { - props.target.delete(); - return true; - } catch (err) { - setError(takeError(err)); - setProcessing(false); - return false; - } - }, - }, - { - children: ( - - ), - onClick: onClose, - palette: "plain", - }, - ]} - content={ - - } - disabled={processing} - error={error} - /> - ); - } - case "create_invite": { - const [code, setCode] = useState("abcdef"); - const { writeClipboard } = useIntermediate(); - - useEffect(() => { - setProcessing(true); - - props.target - .createInvite() - .then(({ _id }) => setCode(_id)) - .catch((err) => setError(takeError(err))) - .finally(() => setProcessing(false)); - }, [props.target]); - - return ( - } - actions={[ - { - children: ( - - ), - confirmation: true, - onClick: onClose, - }, - { - children: , - onClick: () => - writeClipboard( - `${window.location.protocol}//${window.location.host}/invite/${code}`, - ), - }, - ]} - content={ - processing ? ( - - ) : ( -
- - {code} -
- ) - } - disabled={processing} - error={error} - /> - ); - } - case "kick_member": { - return ( - } - actions={[ - { - children: ( - - ), - palette: "error", - confirmation: true, - onClick: async () => { - setProcessing(true); - - try { - client.members - .getKey({ - server: props.target._id, - user: props.user._id, - }) - ?.kick(); - - return true; - } catch (err) { - setError(takeError(err)); - setProcessing(false); - return false; - } - }, - }, - { - children: ( - - ), - onClick: onClose, - }, - ]} - content={ -
- - -
- } - disabled={processing} - error={error} - /> - ); - } - case "ban_member": { - const [reason, setReason] = useState(undefined); - - return ( - } - actions={[ - { - children: ( - - ), - palette: "error", - - confirmation: true, - onClick: async () => { - setProcessing(true); - - try { - await props.target.banUser(props.user._id, { - reason, - }); - - return true; - } catch (err) { - setError(takeError(err)); - setProcessing(false); - return false; - } - }, - }, - { - children: ( - - ), - onClick: onClose, - }, - ]} - content={ -
- - - - - - - setReason(e.currentTarget.value) - } - /> -
- } - disabled={processing} - error={error} - /> - ); - } - case "create_channel": { - const [name, setName] = useState(""); - const [type, setType] = useState<"Text" | "Voice">("Text"); - const history = useHistory(); - - return ( - } - actions={[ - { - confirmation: true, - palette: "secondary", - - children: ( - - ), - onClick: async () => { - setProcessing(true); - - try { - const channel = - await props.target.createChannel({ - type, - name, - }); - - if (props.cb) { - props.cb(channel as any); - } else { - history.push( - `/server/${props.target._id}/channel/${channel._id}`, - ); - } - - return true; - } catch (err) { - setError(takeError(err)); - setProcessing(false); - return false; - } - }, - }, - { - children: ( - - ), - onClick: onClose, - }, - ]} - content={ - <> - - - - - } - value={type === "Text"} - onSelect={() => setType("Text")} - /> - - } - value={type === "Voice"} - onSelect={() => setType("Voice")} - /> - - - - setName(e.currentTarget.value)} - /> - - } - disabled={processing} - error={error} - /> - ); - } - case "create_category": { - const [name, setName] = useState(""); - - return ( - } - actions={[ - { - confirmation: true, - palette: "secondary", - children: ( - - ), - onClick: async () => { - setProcessing(true); - try { - props.target.edit({ - categories: [ - ...(props.target.categories ?? []), - { - id: ulid(), - title: name, - channels: [], - }, - ], - }); - - setProcessing(false); - return true; - } catch (err) { - setError(takeError(err)); - setProcessing(false); - return false; - } - }, - }, - { - children: ( - - ), - onClick: onClose, - }, - ]} - content={ - <> - - - - setName(e.currentTarget.value)} - /> - - } - disabled={processing} - error={error} - /> - ); - } - default: - return null; - } -}); diff --git a/src/context/intermediate/popovers/UserPicker.module.scss b/src/context/intermediate/popovers/UserPicker.module.scss deleted file mode 100644 index f0c1e9a5..00000000 --- a/src/context/intermediate/popovers/UserPicker.module.scss +++ /dev/null @@ -1,5 +0,0 @@ -.list { - max-width: 100%; - max-height: 360px; - overflow-y: scroll; -} diff --git a/src/context/revoltjs/FileUploads.tsx b/src/context/revoltjs/FileUploads.tsx index 4ab39cbc..f0887c90 100644 --- a/src/context/revoltjs/FileUploads.tsx +++ b/src/context/revoltjs/FileUploads.tsx @@ -13,7 +13,6 @@ import { determineFileSize } from "../../lib/fileSize"; import { useClient } from "../../controllers/client/ClientController"; import { modalController } from "../../controllers/modals/ModalController"; -import { useIntermediate } from "../intermediate/Intermediate"; import { takeError } from "./util"; type BehaviourType = @@ -112,7 +111,6 @@ export function grabFiles( export function FileUploader(props: Props) { const { fileType, maxFileSize, remove } = props; - const { openScreen } = useIntermediate(); const client = useClient(); const [uploading, setUploading] = useState(false); @@ -243,7 +241,7 @@ export function FileUploader(props: Props) { document.removeEventListener("dragover", dragover); document.removeEventListener("drop", drop); }; - }, [openScreen, props, props.append]); + }, [props, props.append]); } if (props.style === "icon" || props.style === "banner") { diff --git a/src/controllers/client/Session.tsx b/src/controllers/client/Session.tsx index 442b65d0..f1360e26 100644 --- a/src/controllers/client/Session.tsx +++ b/src/controllers/client/Session.tsx @@ -3,8 +3,6 @@ import { API, Client } from "revolt.js"; import { state } from "../../mobx/State"; -import { __thisIsAHack } from "../../context/intermediate/Intermediate"; - import { modalController } from "../modals/ModalController"; /** diff --git a/src/controllers/modals/ModalRenderer.tsx b/src/controllers/modals/ModalRenderer.tsx index 712a4dc4..1b51dcab 100644 --- a/src/controllers/modals/ModalRenderer.tsx +++ b/src/controllers/modals/ModalRenderer.tsx @@ -1,10 +1,13 @@ import { observer } from "mobx-react-lite"; +import { Prompt, useHistory } from "react-router-dom"; import { useEffect } from "preact/hooks"; import { modalController } from "./ModalController"; export default observer(() => { + const history = useHistory(); + useEffect(() => { function keyUp(event: KeyboardEvent) { if (event.key === "Escape") { @@ -18,5 +21,22 @@ export default observer(() => { return () => document.removeEventListener("keyup", keyUp); }, []); - return modalController.rendered; + return ( + <> + {modalController.rendered} + { + if (action === "POP") { + modalController.pop("close"); + setTimeout(() => history.push(history.location), 0); + + return false; + } + + return true; + }} + /> + + ); }); diff --git a/src/controllers/modals/components/ImportTheme.tsx b/src/controllers/modals/components/ImportTheme.tsx new file mode 100644 index 00000000..67071e61 --- /dev/null +++ b/src/controllers/modals/components/ImportTheme.tsx @@ -0,0 +1,32 @@ +import { Text } from "preact-i18n"; + +import { ModalForm } from "@revoltchat/ui"; + +import { state } from "../../../mobx/State"; + +import { ModalProps } from "../types"; + +/** + * Import theme modal + */ +export default function ImportTheme({ ...props }: ModalProps<"import_theme">) { + return ( + } + schema={{ + data: "text", + }} + data={{ + data: { + field: ( + + ) as React.ReactChild, + }, + }} + callback={async ({ data }) => + state.settings.theme.hydrate(JSON.parse(data)) + } + /> + ); +} diff --git a/src/controllers/modals/types.ts b/src/controllers/modals/types.ts index 1bad3bb2..1275fe4c 100644 --- a/src/controllers/modals/types.ts +++ b/src/controllers/modals/types.ts @@ -176,6 +176,9 @@ export type Modal = { type: "create_category"; target: Server; } + | { + type: "import_theme"; + } ); export type ModalProps = Modal & { type: T } & { diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx index 1fea137d..ac080531 100644 --- a/src/lib/ContextMenus.tsx +++ b/src/lib/ContextMenus.tsx @@ -26,7 +26,6 @@ import { useApplicationState } from "../mobx/State"; import { QueuedMessage } from "../mobx/stores/MessageQueue"; import { NotificationState } from "../mobx/stores/NotificationOptions"; -import { Screen, useIntermediate } from "../context/intermediate/Intermediate"; import { takeError } from "../context/revoltjs/util"; import CMNotifications from "./contextmenu/CMNotifications"; @@ -116,7 +115,6 @@ type Action = // ! FIXME: I dare someone to re-write this // Tip: This should just be split into separate context menus per logical area. export default function ContextMenus() { - const { openScreen, writeClipboard } = useIntermediate(); const session = useSession()!; const client = session.client!; const userId = client.user!._id; @@ -130,7 +128,7 @@ export default function ContextMenus() { (async () => { switch (data.action) { case "copy_id": - writeClipboard(data.id); + modalController.writeText(data.id); break; case "copy_message_link": { @@ -139,11 +137,13 @@ export default function ContextMenus() { if (channel?.channel_type === "TextChannel") pathname = `/server/${channel.server_id}${pathname}`; - writeClipboard(window.origin + pathname); + modalController.writeText(window.origin + pathname); } break; case "copy_selection": - writeClipboard(document.getSelection()?.toString() ?? ""); + modalController.writeText( + document.getSelection()?.toString() ?? "", + ); break; case "mark_as_read": { @@ -227,7 +227,7 @@ export default function ContextMenus() { break; case "copy_text": - writeClipboard(data.content); + modalController.writeText(data.content); break; case "reply_message": @@ -286,7 +286,7 @@ export default function ContextMenus() { case "copy_file_link": { const { filename } = data.attachment; - writeClipboard( + modalController.writeText( // ! FIXME: do from r.js `${client.generateFileURL( data.attachment, @@ -303,7 +303,7 @@ export default function ContextMenus() { case "copy_link": { - writeClipboard(data.link); + modalController.writeText(data.link); } break; @@ -1022,7 +1022,7 @@ export default function ContextMenus() {
- writeClipboard( + modalController.writeText( client.user!.username, ) }> diff --git a/src/pages/RevoltApp.tsx b/src/pages/RevoltApp.tsx index c04917ab..23849dd6 100644 --- a/src/pages/RevoltApp.tsx +++ b/src/pages/RevoltApp.tsx @@ -7,8 +7,6 @@ import { useEffect, useState } from "preact/hooks"; import ContextMenus from "../lib/ContextMenus"; import { isTouchscreenDevice } from "../lib/isTouchscreenDevice"; -import Popovers from "../context/intermediate/Popovers"; - import { Titlebar } from "../components/native/Titlebar"; import BottomNavigation from "../components/navigation/BottomNavigation"; import LeftSidebar from "../components/navigation/LeftSidebar"; @@ -225,7 +223,6 @@ export default function App() { - diff --git a/src/pages/channels/actions/HeaderActions.tsx b/src/pages/channels/actions/HeaderActions.tsx index 04cbe198..cf13311b 100644 --- a/src/pages/channels/actions/HeaderActions.tsx +++ b/src/pages/channels/actions/HeaderActions.tsx @@ -21,8 +21,6 @@ import { voiceState, VoiceStatus } from "../../../lib/vortex/VoiceState"; import { useApplicationState } from "../../../mobx/State"; import { SIDEBAR_MEMBERS } from "../../../mobx/stores/Layout"; -import { useIntermediate } from "../../../context/intermediate/Intermediate"; - import UpdateIndicator from "../../../components/common/UpdateIndicator"; import { modalController } from "../../../controllers/modals/ModalController"; import { ChannelHeaderProps } from "../ChannelHeader"; @@ -74,7 +72,6 @@ const SearchBar = styled.div` export default function HeaderActions({ channel }: ChannelHeaderProps) { const layout = useApplicationState().layout; - const { openScreen } = useIntermediate(); const history = useHistory(); function slideOpen() { diff --git a/src/pages/channels/messaging/MessageArea.tsx b/src/pages/channels/messaging/MessageArea.tsx index c35878d9..d0ae8a5f 100644 --- a/src/pages/channels/messaging/MessageArea.tsx +++ b/src/pages/channels/messaging/MessageArea.tsx @@ -23,10 +23,9 @@ import { internalEmit, internalSubscribe } from "../../../lib/eventEmitter"; import { getRenderer } from "../../../lib/renderer/Singleton"; import { ScrollState } from "../../../lib/renderer/types"; -import { IntermediateContext } from "../../../context/intermediate/Intermediate"; - import { useSession } from "../../../controllers/client/ClientController"; import RequiresOnline from "../../../controllers/client/jsx/RequiresOnline"; +import { modalController } from "../../../controllers/modals/ModalController"; import ConversationStart from "./ConversationStart"; import MessageRenderer from "./MessageRenderer"; @@ -63,7 +62,6 @@ export const MESSAGE_AREA_PADDING = 82; export const MessageArea = observer(({ last_id, channel }: Props) => { const history = useHistory(); const session = useSession()!; - const { focusTaken } = useContext(IntermediateContext); // ? Required data for message links. const { message } = useParams<{ message: string }>(); @@ -303,7 +301,7 @@ export const MessageArea = observer(({ last_id, channel }: Props) => { // ? Scroll to bottom when pressing 'Escape'. useEffect(() => { function keyUp(e: KeyboardEvent) { - if (e.key === "Escape" && !focusTaken) { + if (e.key === "Escape" && !modalController.isVisible) { renderer.jumpToBottom(true); internalEmit("TextArea", "focus", "message"); } @@ -311,7 +309,7 @@ export const MessageArea = observer(({ last_id, channel }: Props) => { document.body.addEventListener("keyup", keyUp); return () => document.body.removeEventListener("keyup", keyUp); - }, [renderer, ref, focusTaken]); + }, [renderer, ref]); return ( { function keyUp(e: KeyboardEvent) { - if (e.key === "Escape" && !focusTaken) { + if (e.key === "Escape" && !modalController.isVisible) { finish(); } } document.body.addEventListener("keyup", keyUp); return () => document.body.removeEventListener("keyup", keyUp); - }, [focusTaken, finish]); + }, [finish]); const { onChange, diff --git a/src/pages/channels/voice/VoiceHeader.tsx b/src/pages/channels/voice/VoiceHeader.tsx index 89ef577c..618baaa2 100644 --- a/src/pages/channels/voice/VoiceHeader.tsx +++ b/src/pages/channels/voice/VoiceHeader.tsx @@ -16,8 +16,6 @@ import { Button } from "@revoltchat/ui"; import { voiceState, VoiceStatus } from "../../../lib/vortex/VoiceState"; -import { useIntermediate } from "../../../context/intermediate/Intermediate"; - import Tooltip from "../../../components/common/Tooltip"; import UserIcon from "../../../components/common/user/UserIcon"; import { useClient } from "../../../controllers/client/ClientController"; @@ -85,8 +83,6 @@ const VoiceBase = styled.div` export default observer(({ id }: Props) => { if (voiceState.roomId !== id) return null; - const { openScreen } = useIntermediate(); - const client = useClient(); const self = client.users.get(client.user!._id); diff --git a/src/pages/discover/Discover.tsx b/src/pages/discover/Discover.tsx index 66fb7268..666daeed 100644 --- a/src/pages/discover/Discover.tsx +++ b/src/pages/discover/Discover.tsx @@ -12,7 +12,8 @@ import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice"; import { useApplicationState } from "../../mobx/State"; import { Overrides } from "../../context/Theme"; -import { useIntermediate } from "../../context/intermediate/Intermediate"; + +import { modalController } from "../../controllers/modals/ModalController"; const Container = styled.div` flex-grow: 1; @@ -85,7 +86,6 @@ const REMOTE = "https://rvlt.gg"; export default function Discover() { const state = useApplicationState(); - const { openLink } = useIntermediate(); const history = useHistory(); const { pathname, search } = useLocation(); @@ -137,7 +137,7 @@ export default function Discover() { break; } case "navigate": { - openLink(data.url); + modalController.openLink(data.url); break; } case "applyTheme": { diff --git a/src/pages/friends/Friend.tsx b/src/pages/friends/Friend.tsx index 7e3c1ef1..4bdd9c7c 100644 --- a/src/pages/friends/Friend.tsx +++ b/src/pages/friends/Friend.tsx @@ -14,8 +14,6 @@ import { IconButton } from "@revoltchat/ui"; import { stopPropagation } from "../../lib/stopPropagation"; import { voiceState } from "../../lib/vortex/VoiceState"; -import { useIntermediate } from "../../context/intermediate/Intermediate"; - import UserIcon from "../../components/common/user/UserIcon"; import UserStatus from "../../components/common/user/UserStatus"; import { modalController } from "../../controllers/modals/ModalController"; @@ -26,7 +24,6 @@ interface Props { export const Friend = observer(({ user }: Props) => { const history = useHistory(); - const { openScreen } = useIntermediate(); const actions: Children[] = []; let subtext: Children = null; diff --git a/src/pages/friends/Friends.tsx b/src/pages/friends/Friends.tsx index a479b46b..e4374a26 100644 --- a/src/pages/friends/Friends.tsx +++ b/src/pages/friends/Friends.tsx @@ -12,8 +12,6 @@ import { IconButton } from "@revoltchat/ui"; import { TextReact } from "../../lib/i18n"; import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice"; -import { useIntermediate } from "../../context/intermediate/Intermediate"; - import CollapsibleSection from "../../components/common/CollapsibleSection"; import Tooltip from "../../components/common/Tooltip"; import UserIcon from "../../components/common/user/UserIcon"; @@ -23,8 +21,6 @@ import { modalController } from "../../controllers/modals/ModalController"; import { Friend } from "./Friend"; export default observer(() => { - const { openScreen } = useIntermediate(); - const client = useClient(); const users = [...client.users.values()]; users.sort((a, b) => a.username.localeCompare(b.username)); diff --git a/src/pages/home/Home.tsx b/src/pages/home/Home.tsx index 67784147..75609150 100644 --- a/src/pages/home/Home.tsx +++ b/src/pages/home/Home.tsx @@ -23,8 +23,6 @@ import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice"; import { useApplicationState } from "../../mobx/State"; -import { useIntermediate } from "../../context/intermediate/Intermediate"; - import wideSVG from "/assets/wide.svg"; import { PageHeader } from "../../components/ui/Header"; @@ -45,7 +43,6 @@ const Overlay = styled.div` `; export default observer(() => { - const { openScreen } = useIntermediate(); const client = useClient(); const state = useApplicationState(); diff --git a/src/pages/settings/ServerSettings.tsx b/src/pages/settings/ServerSettings.tsx index 72f2925f..d008cf0a 100644 --- a/src/pages/settings/ServerSettings.tsx +++ b/src/pages/settings/ServerSettings.tsx @@ -15,8 +15,6 @@ import { Text } from "preact-i18n"; import { LineDivider } from "@revoltchat/ui"; -import { useIntermediate } from "../../context/intermediate/Intermediate"; - import ButtonItem from "../../components/navigation/items/ButtonItem"; import { useClient } from "../../controllers/client/ClientController"; import RequiresOnline from "../../controllers/client/jsx/RequiresOnline"; @@ -30,7 +28,6 @@ import { Overview } from "./server/Overview"; import { Roles } from "./server/Roles"; export default observer(() => { - const { openScreen } = useIntermediate(); const { server: sid } = useParams<{ server: string }>(); const client = useClient(); const server = client.servers.get(sid); diff --git a/src/pages/settings/Settings.tsx b/src/pages/settings/Settings.tsx index 022f0c85..18566e5c 100644 --- a/src/pages/settings/Settings.tsx +++ b/src/pages/settings/Settings.tsx @@ -33,8 +33,6 @@ import { LineDivider } from "@revoltchat/ui"; import { useApplicationState } from "../../mobx/State"; -import { useIntermediate } from "../../context/intermediate/Intermediate"; - import UserIcon from "../../components/common/user/UserIcon"; import { Username } from "../../components/common/user/UserShort"; import UserStatus from "../../components/common/user/UserStatus"; @@ -121,7 +119,6 @@ const AccountHeader = styled.div` export default observer(() => { const history = useHistory(); const client = useClient(); - const { openScreen } = useIntermediate(); const experiments = useApplicationState().experiments; function switchPage(to?: string) { diff --git a/src/pages/settings/panes/MyBots.tsx b/src/pages/settings/panes/MyBots.tsx index 158ca952..122ae7ff 100644 --- a/src/pages/settings/panes/MyBots.tsx +++ b/src/pages/settings/panes/MyBots.tsx @@ -23,7 +23,6 @@ import { internalEmit } from "../../../lib/eventEmitter"; import { useTranslation } from "../../../lib/i18n"; import { stopPropagation } from "../../../lib/stopPropagation"; -import { useIntermediate } from "../../../context/intermediate/Intermediate"; import { FileUploader } from "../../../context/revoltjs/FileUploads"; import AutoComplete, { @@ -88,7 +87,6 @@ function BotCard({ bot, onDelete, onUpdate }: Props) { ); const [interactionsRef, setInteractionsRef] = useState(null); - const { writeClipboard, openScreen } = useIntermediate(); const [profile, setProfile] = useState( undefined, @@ -267,7 +265,9 @@ function BotCard({ bot, onDelete, onUpdate }: Props) { }> - writeClipboard(user!._id) + modalController.writeText( + user!._id, + ) }> {user!._id} @@ -335,7 +335,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) { } - onClick={() => writeClipboard(bot.token)} + onClick={() => modalController.writeText(bot.token)} description={ <> {"••••• "} @@ -475,7 +475,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) { <>