feat(modal): port Clipboard

This commit is contained in:
Paul Makles 2022-06-18 12:33:22 +01:00
parent d10bd96900
commit 241b9cd27b
9 changed files with 49 additions and 27 deletions

View file

@ -12,6 +12,7 @@ import { determineLink } from "../../lib/links";
import { useApplicationState } from "../../mobx/State"; import { useApplicationState } from "../../mobx/State";
import { modalController } from "../modals";
import Modals from "./Modals"; import Modals from "./Modals";
export type Screen = export type Screen =
@ -171,13 +172,7 @@ export default function Intermediate(props: Props) {
return true; return true;
}, },
openScreen: (screen: Screen) => openScreen(screen), openScreen: (screen: Screen) => openScreen(screen),
writeClipboard: (text: string) => { writeClipboard: (a: string) => modalController.writeText(a),
if (navigator.clipboard) {
navigator.clipboard.writeText(text);
} else {
actions.openScreen({ id: "clipboard", text });
}
},
}; };
// eslint-disable-next-line // eslint-disable-next-line
}, []); }, []);

View file

@ -1,6 +1,5 @@
//import { isModalClosing } from "../../components/ui/Modal"; //import { isModalClosing } from "../../components/ui/Modal";
import { Screen } from "./Intermediate"; import { Screen } from "./Intermediate";
import { ClipboardModal } from "./modals/Clipboard";
import { ExternalLinkModal } from "./modals/ExternalLinkPrompt"; import { ExternalLinkModal } from "./modals/ExternalLinkPrompt";
import { InputModal } from "./modals/Input"; import { InputModal } from "./modals/Input";
import { OnboardingModal } from "./modals/Onboarding"; import { OnboardingModal } from "./modals/Onboarding";
@ -22,8 +21,6 @@ export default function Modals({ screen, openScreen }: Props) {
return <PromptModal onClose={onClose} {...screen} />; return <PromptModal onClose={onClose} {...screen} />;
case "_input": case "_input":
return <InputModal onClose={onClose} {...screen} />; return <InputModal onClose={onClose} {...screen} />;
case "clipboard":
return <ClipboardModal onClose={onClose} {...screen} />;
case "onboarding": case "onboarding":
return <OnboardingModal onClose={onClose} {...screen} />; return <OnboardingModal onClose={onClose} {...screen} />;
case "external_link_prompt": case "external_link_prompt":

View file

@ -2,19 +2,18 @@ import { Text } from "preact-i18n";
import { Modal } from "@revoltchat/ui"; import { Modal } from "@revoltchat/ui";
interface Props { import { noopTrue } from "../../../lib/js";
onClose: () => void;
text: string;
}
export function ClipboardModal({ onClose, text }: Props) { import { ModalProps } from "../types";
export default function Clipboard({ text, ...props }: ModalProps<"clipboard">) {
return ( return (
<Modal <Modal
onClose={onClose} {...props}
title={<Text id="app.special.modals.clipboard.unavailable" />} title={<Text id="app.special.modals.clipboard.unavailable" />}
actions={[ actions={[
{ {
onClick: onClose, onClick: noopTrue,
confirmation: true, confirmation: true,
children: <Text id="app.special.modals.actions.close" />, children: <Text id="app.special.modals.actions.close" />,
}, },
@ -25,7 +24,9 @@ export function ClipboardModal({ onClose, text }: Props) {
</p> </p>
)} )}
<Text id="app.special.modals.clipboard.copy" />{" "} <Text id="app.special.modals.clipboard.copy" />{" "}
<code style={{ userSelect: "all" }}>{text}</code> <code style={{ userSelect: "all", wordBreak: "break-all" }}>
{text}
</code>
</Modal> </Modal>
); );
} }

View file

@ -6,7 +6,7 @@ import { noopTrue } from "../../../lib/js";
import { ModalProps } from "../types"; import { ModalProps } from "../types";
export function Error({ error, ...props }: ModalProps<"error">) { export default function Error({ error, ...props }: ModalProps<"error">) {
return ( return (
<Modal <Modal
{...props} {...props}

View file

@ -6,7 +6,11 @@ import { noopTrue } from "../../../lib/js";
import { ModalProps } from "../types"; import { ModalProps } from "../types";
export function ShowToken({ name, token, ...props }: ModalProps<"show_token">) { export default function ShowToken({
name,
token,
...props
}: ModalProps<"show_token">) {
return ( return (
<Modal <Modal
{...props} {...props}
@ -23,7 +27,9 @@ export function ShowToken({ name, token, ...props }: ModalProps<"show_token">) {
children: <Text id="app.special.modals.actions.close" />, children: <Text id="app.special.modals.actions.close" />,
}, },
]}> ]}>
<code style={{ userSelect: "all" }}>{token}</code> <code style={{ userSelect: "all", wordBreak: "break-all" }}>
{token}
</code>
</Modal> </Modal>
); );
} }

View file

@ -10,7 +10,9 @@ import { ModalProps } from "../types";
/** /**
* Confirm whether a user wants to sign out of all other sessions * Confirm whether a user wants to sign out of all other sessions
*/ */
export function SignOutSessions(props: ModalProps<"sign_out_sessions">) { export default function SignOutSessions(
props: ModalProps<"sign_out_sessions">,
) {
const onClick = useCallback(() => { const onClick = useCallback(() => {
props.onDeleting(); props.onDeleting();
props.client.api.delete("/auth/session/all").then(props.onDelete); props.client.api.delete("/auth/session/all").then(props.onDelete);

View file

@ -9,7 +9,7 @@ import { ModalProps } from "../types";
/** /**
* Indicate that the user has been signed out of their account * Indicate that the user has been signed out of their account
*/ */
export function SignedOut(props: ModalProps<"signed_out">) { export default function SignedOut(props: ModalProps<"signed_out">) {
return ( return (
<Modal <Modal
{...props} {...props}

View file

@ -9,14 +9,15 @@ import type { Client, API } from "revolt.js";
import { ulid } from "ulid"; import { ulid } from "ulid";
import Changelog from "./components/Changelog"; import Changelog from "./components/Changelog";
import { Error } from "./components/Error"; import Clipboard from "./components/Clipboard";
import Error from "./components/Error";
import MFAEnableTOTP from "./components/MFAEnableTOTP"; import MFAEnableTOTP from "./components/MFAEnableTOTP";
import MFAFlow from "./components/MFAFlow"; import MFAFlow from "./components/MFAFlow";
import MFARecovery from "./components/MFARecovery"; import MFARecovery from "./components/MFARecovery";
import OutOfDate from "./components/OutOfDate"; import OutOfDate from "./components/OutOfDate";
import { ShowToken } from "./components/ShowToken"; import ShowToken from "./components/ShowToken";
import { SignOutSessions } from "./components/SignOutSessions"; import SignOutSessions from "./components/SignOutSessions";
import { SignedOut } from "./components/SignedOut"; import SignedOut from "./components/SignedOut";
import { Modal } from "./types"; import { Modal } from "./types";
type Components = Record<string, React.FC<any>>; type Components = Record<string, React.FC<any>>;
@ -140,10 +141,26 @@ class ModalControllerExtended extends ModalController<Modal> {
), ),
); );
} }
/**
* Write text to the clipboard
* @param text Text to write
*/
writeText(text: string) {
if (navigator.clipboard) {
navigator.clipboard.writeText(text);
} else {
this.push({
type: "clipboard",
text,
});
}
}
} }
export const modalController = new ModalControllerExtended({ export const modalController = new ModalControllerExtended({
changelog: Changelog, changelog: Changelog,
clipboard: Clipboard,
error: Error, error: Error,
mfa_flow: MFAFlow, mfa_flow: MFAFlow,
mfa_recovery: MFARecovery, mfa_recovery: MFARecovery,

View file

@ -47,6 +47,10 @@ export type Modal = {
type: "error"; type: "error";
error: string; error: string;
} }
| {
type: "clipboard";
text: string;
}
| { | {
type: "signed_out"; type: "signed_out";
} }