Add new ShareDialog
This commit is contained in:
@@ -13,7 +13,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
.mx_ShareDialog .mx_ShareDialog_content {
|
||||
margin: 10px 0;
|
||||
|
||||
text-align: center;
|
||||
.mx_CopyableText {
|
||||
width: unset; /* full width */
|
||||
|
||||
@@ -27,27 +27,51 @@ Please see LICENSE files in the repository root for full details.
|
||||
}
|
||||
}
|
||||
|
||||
.mx_ShareDialog_split {
|
||||
.mx_ShareDialog_url {
|
||||
text-align: center;
|
||||
color: var(--cpd-color-text-secondary);
|
||||
overflow-wrap: break-word;
|
||||
max-width: 400px;
|
||||
}
|
||||
.mx_ShareDialog_checkbox {
|
||||
display: inline-block;
|
||||
margin: var(--cpd-space-4x) 0;
|
||||
}
|
||||
.mx_ShareDialog_button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mx_ShareDialog_qrCode {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mx_ShareDialog_qrCode img {
|
||||
margin: 0 var(--cpd-space-8x);
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.mx_LegacyShareDialog_split {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.mx_ShareDialog_qrcode_container {
|
||||
.mx_LegacyShareDialog_qrcode_container {
|
||||
float: left;
|
||||
height: 256px;
|
||||
width: 256px;
|
||||
margin-right: 64px;
|
||||
}
|
||||
|
||||
.mx_ShareDialog_qrcode_container + .mx_ShareDialog_social_container {
|
||||
.mx_LegacyShareDialog_qrcode_container + .mx_LegacyShareDialog_social_container {
|
||||
width: 299px;
|
||||
}
|
||||
|
||||
.mx_ShareDialog_social_container {
|
||||
.mx_LegacyShareDialog_social_container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mx_ShareDialog_social_icon {
|
||||
.mx_LegacyShareDialog_social_icon {
|
||||
display: inline-grid;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
@@ -9,51 +9,20 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import * as React from "react";
|
||||
import { Room, RoomMember, MatrixEvent, User } from "matrix-js-sdk/src/matrix";
|
||||
import { Button, Text } from "@vector-im/compound-web";
|
||||
import LinkIcon from "@vector-im/compound-design-tokens/assets/web/icons/link";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import QRCode from "../elements/QRCode";
|
||||
import { RoomPermalinkCreator, makeUserPermalink } from "../../../utils/permalinks/Permalinks";
|
||||
import { selectText } from "../../../utils/strings";
|
||||
import { copyPlaintext, selectText } from "../../../utils/strings";
|
||||
import StyledCheckbox from "../elements/StyledCheckbox";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { UIFeature } from "../../../settings/UIFeature";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import CopyableText from "../elements/CopyableText";
|
||||
import { XOR } from "../../../@types/common";
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
const socials = [
|
||||
{
|
||||
name: "Facebook",
|
||||
img: require("../../../../res/img/social/facebook.png"),
|
||||
url: (url: string) => `https://www.facebook.com/sharer/sharer.php?u=${url}`,
|
||||
},
|
||||
{
|
||||
name: "Twitter",
|
||||
img: require("../../../../res/img/social/twitter-2.png"),
|
||||
url: (url: string) => `https://twitter.com/home?status=${url}`,
|
||||
},
|
||||
/* // icon missing
|
||||
name: 'Google Plus',
|
||||
img: 'img/social/',
|
||||
url: (url) => `https://plus.google.com/share?url=${url}`,
|
||||
},*/ {
|
||||
name: "LinkedIn",
|
||||
img: require("../../../../res/img/social/linkedin.png"),
|
||||
url: (url: string) => `https://www.linkedin.com/shareArticle?mini=true&url=${url}`,
|
||||
},
|
||||
{
|
||||
name: "Reddit",
|
||||
img: require("../../../../res/img/social/reddit.png"),
|
||||
url: (url: string) => `https://www.reddit.com/submit?url=${url}`,
|
||||
},
|
||||
{
|
||||
name: "email",
|
||||
img: require("../../../../res/img/social/email-1.png"),
|
||||
url: (url: string) => `mailto:?body=${url}`,
|
||||
},
|
||||
];
|
||||
/* eslint-enable @typescript-eslint/no-require-imports */
|
||||
import { ButtonEvent } from "../elements/AccessibleButton";
|
||||
import CopyableText from "../elements/CopyableText";
|
||||
|
||||
interface BaseProps {
|
||||
/**
|
||||
@@ -91,7 +60,168 @@ interface IState {
|
||||
permalinkCreator: RoomPermalinkCreator | null;
|
||||
}
|
||||
|
||||
export default class ShareDialog extends React.PureComponent<XOR<Props, EventProps>, IState> {
|
||||
// TODO: make this a Rect.FC
|
||||
export class ShareDialog extends React.PureComponent<XOR<Props, EventProps>, IState> {
|
||||
public constructor(props: XOR<Props, EventProps>) {
|
||||
super(props);
|
||||
|
||||
let permalinkCreator: RoomPermalinkCreator | null = null;
|
||||
if (props.target instanceof Room) {
|
||||
permalinkCreator = new RoomPermalinkCreator(props.target);
|
||||
permalinkCreator.load();
|
||||
}
|
||||
|
||||
this.state = {
|
||||
// MatrixEvent defaults to share linkSpecificEvent
|
||||
linkSpecificEvent: this.props.target instanceof MatrixEvent,
|
||||
permalinkCreator,
|
||||
};
|
||||
}
|
||||
|
||||
public static onLinkClick(e: React.MouseEvent): void {
|
||||
e.preventDefault();
|
||||
selectText(e.currentTarget);
|
||||
}
|
||||
|
||||
private onLinkSpecificEventCheckboxClick = (): void => {
|
||||
this.setState({
|
||||
linkSpecificEvent: !this.state.linkSpecificEvent,
|
||||
});
|
||||
};
|
||||
|
||||
private getUrl(): string {
|
||||
if (this.props.target instanceof URL) {
|
||||
return this.props.target.toString();
|
||||
} else if (this.props.target instanceof Room) {
|
||||
if (this.state.linkSpecificEvent) {
|
||||
const events = this.props.target.getLiveTimeline().getEvents();
|
||||
return this.state.permalinkCreator!.forEvent(events[events.length - 1].getId()!);
|
||||
} else {
|
||||
return this.state.permalinkCreator!.forShareableRoom();
|
||||
}
|
||||
} else if (this.props.target instanceof User || this.props.target instanceof RoomMember) {
|
||||
return makeUserPermalink(this.props.target.userId);
|
||||
} else if (this.state.linkSpecificEvent) {
|
||||
return this.props.permalinkCreator!.forEvent(this.props.target.getId()!);
|
||||
} else {
|
||||
return this.props.permalinkCreator!.forShareableRoom();
|
||||
}
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
let title: string | undefined;
|
||||
let checkbox: JSX.Element | undefined;
|
||||
|
||||
if (this.props.target instanceof URL) {
|
||||
title = this.props.customTitle ?? _t("share|title_link");
|
||||
} else if (this.props.target instanceof Room) {
|
||||
title = this.props.customTitle ?? _t("share|title_room");
|
||||
|
||||
const events = this.props.target.getLiveTimeline().getEvents();
|
||||
if (events.length > 0) {
|
||||
checkbox = (
|
||||
<div className="mx_ShareDialog_checkbox">
|
||||
<StyledCheckbox
|
||||
checked={this.state.linkSpecificEvent}
|
||||
onChange={this.onLinkSpecificEventCheckboxClick}
|
||||
>
|
||||
{_t("share|permalink_most_recent")}
|
||||
</StyledCheckbox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
} else if (this.props.target instanceof User || this.props.target instanceof RoomMember) {
|
||||
title = this.props.customTitle ?? _t("share|title_user");
|
||||
} else if (this.props.target instanceof MatrixEvent) {
|
||||
title = this.props.customTitle ?? _t("share|title_message");
|
||||
checkbox = (
|
||||
<div>
|
||||
<StyledCheckbox
|
||||
checked={this.state.linkSpecificEvent}
|
||||
onChange={this.onLinkSpecificEventCheckboxClick}
|
||||
>
|
||||
{_t("share|permalink_message")}
|
||||
</StyledCheckbox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const matrixToUrl = this.getUrl();
|
||||
|
||||
const showQrCode = SettingsStore.getValue(UIFeature.ShareQRCode);
|
||||
const onButtonClick = async (e: ButtonEvent): Promise<void> => {
|
||||
e.preventDefault();
|
||||
|
||||
await copyPlaintext(matrixToUrl);
|
||||
this.props.onFinished();
|
||||
};
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
title={title}
|
||||
fixedWidth={false}
|
||||
className="mx_ShareDialog"
|
||||
contentId="mx_Dialog_content"
|
||||
onFinished={this.props.onFinished}
|
||||
>
|
||||
{this.props.subtitle && <p>{this.props.subtitle}</p>}
|
||||
<div className="mx_ShareDialog_content">
|
||||
{showQrCode && <QRCode className="mx_ShareDialog_qrCode" data={matrixToUrl} />}
|
||||
<Text className="mx_ShareDialog_url" size="sm" weight="semibold">
|
||||
{matrixToUrl}
|
||||
</Text>
|
||||
{checkbox}
|
||||
<Button
|
||||
className="mx_ShareDialog_button mx_Dialog_nonDialogButton"
|
||||
Icon={LinkIcon}
|
||||
onClick={onButtonClick}
|
||||
data-testid="modal_inviteLink"
|
||||
>
|
||||
{_t("action|copy_link")}
|
||||
</Button>
|
||||
</div>
|
||||
</BaseDialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// LEGACY SHARE DIALOG
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
const socials = [
|
||||
{
|
||||
name: "Facebook",
|
||||
img: require("../../../../res/img/social/facebook.png"),
|
||||
url: (url: string) => `https://www.facebook.com/sharer/sharer.php?u=${url}`,
|
||||
},
|
||||
{
|
||||
name: "Twitter",
|
||||
img: require("../../../../res/img/social/twitter-2.png"),
|
||||
url: (url: string) => `https://twitter.com/home?status=${url}`,
|
||||
},
|
||||
/* // icon missing
|
||||
name: 'Google Plus',
|
||||
img: 'img/social/',
|
||||
url: (url) => `https://plus.google.com/share?url=${url}`,
|
||||
},*/ {
|
||||
name: "LinkedIn",
|
||||
img: require("../../../../res/img/social/linkedin.png"),
|
||||
url: (url: string) => `https://www.linkedin.com/shareArticle?mini=true&url=${url}`,
|
||||
},
|
||||
{
|
||||
name: "Reddit",
|
||||
img: require("../../../../res/img/social/reddit.png"),
|
||||
url: (url: string) => `https://www.reddit.com/submit?url=${url}`,
|
||||
},
|
||||
{
|
||||
name: "email",
|
||||
img: require("../../../../res/img/social/email-1.png"),
|
||||
url: (url: string) => `mailto:?body=${url}`,
|
||||
},
|
||||
];
|
||||
/* eslint-enable @typescript-eslint/no-require-imports */
|
||||
|
||||
export default class LegacyShareDialog extends React.PureComponent<XOR<Props, EventProps>, IState> {
|
||||
public constructor(props: XOR<Props, EventProps>) {
|
||||
super(props);
|
||||
|
||||
@@ -187,14 +317,14 @@ export default class ShareDialog extends React.PureComponent<XOR<Props, EventPro
|
||||
qrSocialSection = (
|
||||
<>
|
||||
<hr />
|
||||
<div className="mx_ShareDialog_split">
|
||||
<div className="mx_LegacyShareDialog_split">
|
||||
{showQrCode && (
|
||||
<div className="mx_ShareDialog_qrcode_container">
|
||||
<div className="mx_LegacyShareDialog_qrcode_container">
|
||||
<QRCode data={matrixToUrl} width={256} />
|
||||
</div>
|
||||
)}
|
||||
{showSocials && (
|
||||
<div className="mx_ShareDialog_social_container">
|
||||
<div className="mx_LegacyShareDialog_social_container">
|
||||
{socials.map((social) => (
|
||||
<a
|
||||
rel="noreferrer noopener"
|
||||
@@ -202,7 +332,7 @@ export default class ShareDialog extends React.PureComponent<XOR<Props, EventPro
|
||||
key={social.name}
|
||||
title={social.name}
|
||||
href={social.url(encodedUrl)}
|
||||
className="mx_ShareDialog_social_icon"
|
||||
className="mx_LegacyShareDialog_social_icon"
|
||||
>
|
||||
<img src={social.img} alt={social.name} height={64} width={64} />
|
||||
</a>
|
||||
|
||||
@@ -12,7 +12,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { EventType, JoinRule, Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import Modal from "../../../../Modal";
|
||||
import ShareDialog from "../../dialogs/ShareDialog";
|
||||
import { ShareDialog } from "../../dialogs/ShareDialog";
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import SettingsStore from "../../../../settings/SettingsStore";
|
||||
import { calculateRoomVia } from "../../../../utils/permalinks/Permalinks";
|
||||
|
||||
@@ -75,7 +75,7 @@ describe("ShareDialog", () => {
|
||||
return originalGetValue(feature);
|
||||
});
|
||||
const { container } = render(<ShareDialog target={room} onFinished={jest.fn()} />, getWrapper());
|
||||
const qrCodesVisible = container.getElementsByClassName("mx_ShareDialog_qrcode_container").length > 0;
|
||||
const qrCodesVisible = container.getElementsByClassName("mx_LegacyShareDialog_qrcode_container").length > 0;
|
||||
expect(qrCodesVisible).toBe(true);
|
||||
});
|
||||
|
||||
@@ -86,7 +86,7 @@ describe("ShareDialog", () => {
|
||||
return originalGetValue(feature);
|
||||
});
|
||||
const { container } = render(<ShareDialog target={room} onFinished={jest.fn()} />, getWrapper());
|
||||
const qrCodesVisible = container.getElementsByClassName("mx_ShareDialog_social_container").length > 0;
|
||||
const qrCodesVisible = container.getElementsByClassName("mx_LegacyShareDialog_social_container").length > 0;
|
||||
expect(qrCodesVisible).toBe(true);
|
||||
});
|
||||
it("renders custom title and subtitle", () => {
|
||||
|
||||
Reference in New Issue
Block a user