Skip to content

Commit 39efc0e

Browse files
authored
Merge pull request #270 from Shailesh351/sb_pwa_8_wc
[Upstream PWA] RocketChat#17649 Add Share Functionality
2 parents c670e54 + 019b89a commit 39efc0e

File tree

13 files changed

+283
-1
lines changed

13 files changed

+283
-1
lines changed

app/lib/client/defaultTabBars.js

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Session } from 'meteor/session';
22

3-
import { TabBar } from '../../ui-utils';
3+
import { TabBar, popover } from '../../ui-utils';
4+
import { share, isShareAvailable } from '../../utils';
45
import { Rooms } from '../../models';
56
import { hasAllPermission } from '../../authorization';
67
import { roomTypes } from '../../utils/client';
@@ -86,3 +87,22 @@ TabBar.addButton({
8687
template: 'keyboardShortcuts',
8788
order: 99,
8889
});
90+
91+
// Add Share button in Room
92+
const shareButton = {
93+
groups: ['channel', 'group', 'direct'],
94+
id: 'share',
95+
i18nTitle: 'Share',
96+
icon: 'share',
97+
template: 'share',
98+
order: 500,
99+
};
100+
101+
if (isShareAvailable()) {
102+
shareButton.action = () => {
103+
share();
104+
popover.close();
105+
};
106+
}
107+
108+
TabBar.addButton(shareButton);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
.share-header-container {
2+
display: flex;
3+
flex-wrap: wrap;
4+
}
5+
6+
.share-icon {
7+
display: inline-block;
8+
9+
box-sizing: border-box;
10+
11+
width: 25%;
12+
min-width: 46px;
13+
14+
padding: 16px 0;
15+
16+
cursor: pointer;
17+
18+
text-align: center;
19+
20+
border: none;
21+
22+
background-color: transparent;
23+
24+
box-shadow: inset 0 0 20px rgba(0, 0, 0, 0);
25+
26+
font-size: 12px;
27+
font-weight: 400;
28+
29+
-webkit-font-smoothing: antialiased;
30+
-moz-osx-font-smoothing: grayscale;
31+
32+
&:hover {
33+
box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.125);
34+
}
35+
}
36+
37+
.share-svg-icon {
38+
display: block;
39+
40+
width: 42px;
41+
height: 36px;
42+
margin: auto;
43+
44+
&__header {
45+
width: 24px;
46+
height: 24px;
47+
}
48+
}
49+
50+
.share-icon-title {
51+
display: block;
52+
53+
padding-top: 10px;
54+
55+
font-size: 14px;
56+
}

app/theme/client/main.css

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
@import 'imports/components/emojiPicker.css';
4949
@import 'imports/components/table.css';
5050
@import 'imports/components/tabs.css';
51+
@import 'imports/components/share.css';
5152

5253
/* Modal */
5354
@import 'imports/components/modal/full-modal.css';

app/ui-share/README.md

Whitespace-only changes.

app/ui-share/client/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import './share.html';
2+
import './share';

app/ui-share/client/share.html

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<template name="share">
2+
<div class="rc-popover__column">
3+
<div class="share-header-container">
4+
<button class="share-icon" data-type="copy">
5+
<svg class="share-svg-icon__header" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="#424242" d="M320 448v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V120c0-13.255 10.745-24 24-24h72v296c0 30.879 25.121 56 56 56h168zm0-344V0H152c-13.255 0-24 10.745-24 24v368c0 13.255 10.745 24 24 24h272c13.255 0 24-10.745 24-24V128H344c-13.2 0-24-10.8-24-24zm120.971-31.029L375.029 7.029A24 24 0 0 0 358.059 0H352v96h96v-6.059a24 24 0 0 0-7.029-16.97z"></path></svg>
6+
<span class="share-icon-title">Copy</span>
7+
</button>
8+
<button class="share-icon" data-type="print">
9+
<svg class="share-svg-icon__header" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#424242" d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
10+
<span class="share-icon-title">Print</span>
11+
</button>
12+
<button class="share-icon" data-type="email">
13+
<svg class="share-svg-icon__header" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path fill="#424242" d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 14H4V8l8 5 8-5v10zm-8-7L4 6h16l-8 5z"/></svg>
14+
<span class="share-icon-title">Email</span>
15+
</button>
16+
<button class="share-icon" data-type="sms">
17+
<svg class="share-svg-icon__header" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#424242" d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM9 11H7V9h2v2zm4 0h-2V9h2v2zm4 0h-2V9h2v2z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
18+
<span class="share-icon-title">SMS</span>
19+
</button>
20+
</div>
21+
22+
<div class="share-header-container">
23+
<button class="share-icon" data-type="facebook">
24+
<svg class="share-svg-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="#3b5998" d="M448 56.7v398.5c0 13.7-11.1 24.7-24.7 24.7H309.1V306.5h58.2l8.7-67.6h-67v-43.2c0-19.6 5.4-32.9 33.5-32.9h35.8v-60.5c-6.2-.8-27.4-2.7-52.2-2.7-51.6 0-87 31.5-87 89.4v49.9h-58.4v67.6h58.4V480H24.7C11.1 480 0 468.9 0 455.3V56.7C0 43.1 11.1 32 24.7 32h398.5c13.7 0 24.8 11.1 24.8 24.7z"></path></svg>
25+
<span class="share-icon-title">Facebook</span>
26+
</button>
27+
<button class="share-icon" data-type="whatsapp">
28+
<svg class="share-svg-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="#075e54" d="M224 122.8c-72.7 0-131.8 59.1-131.9 131.8 0 24.9 7 49.2 20.2 70.1l3.1 5-13.3 48.6 49.9-13.1 4.8 2.9c20.2 12 43.4 18.4 67.1 18.4h.1c72.6 0 133.3-59.1 133.3-131.8 0-35.2-15.2-68.3-40.1-93.2-25-25-58-38.7-93.2-38.7zm77.5 188.4c-3.3 9.3-19.1 17.7-26.7 18.8-12.6 1.9-22.4.9-47.5-9.9-39.7-17.2-65.7-57.2-67.7-59.8-2-2.6-16.2-21.5-16.2-41s10.2-29.1 13.9-33.1c3.6-4 7.9-5 10.6-5 2.6 0 5.3 0 7.6.1 2.4.1 5.7-.9 8.9 6.8 3.3 7.9 11.2 27.4 12.2 29.4s1.7 4.3.3 6.9c-7.6 15.2-15.7 14.6-11.6 21.6 15.3 26.3 30.6 35.4 53.9 47.1 4 2 6.3 1.7 8.6-1 2.3-2.6 9.9-11.6 12.5-15.5 2.6-4 5.3-3.3 8.9-2 3.6 1.3 23.1 10.9 27.1 12.9s6.6 3 7.6 4.6c.9 1.9.9 9.9-2.4 19.1zM400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM223.9 413.2c-26.6 0-52.7-6.7-75.8-19.3L64 416l22.5-82.2c-13.9-24-21.2-51.3-21.2-79.3C65.4 167.1 136.5 96 223.9 96c42.4 0 82.2 16.5 112.2 46.5 29.9 30 47.9 69.8 47.9 112.2 0 87.4-72.7 158.5-160.1 158.5z"></path></svg>
29+
<span class="share-icon-title">WhatsApp</span>
30+
</button>
31+
<button class="share-icon" data-type="twitter">
32+
<svg class="share-svg-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#1da1f2" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg>
33+
<span class="share-icon-title">Twitter</span>
34+
</button>
35+
<button class="share-icon" data-type="linkedin">
36+
<svg class="share-svg-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="#0077b5" d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"></path></svg>
37+
<span class="share-icon-title">LinkedIn</span>
38+
</button>
39+
<button class="share-icon" data-type="telegram">
40+
<svg class="share-svg-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path fill="#0088cc" d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm121.8 169.9l-40.7 191.8c-3 13.6-11.1 16.9-22.4 10.5l-62-45.7-29.9 28.8c-3.3 3.3-6.1 6.1-12.5 6.1l4.4-63.1 114.9-103.8c5-4.4-1.1-6.9-7.7-2.5l-142 89.4-61.2-19.1c-13.3-4.2-13.6-13.3 2.8-19.7l239.1-92.2c11.1-4 20.8 2.7 17.2 19.5z"></path></svg>
41+
<span class="share-icon-title">Telegram</span>
42+
</button>
43+
</div>
44+
</div>
45+
</template>

app/ui-share/client/share.js

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Template } from 'meteor/templating';
2+
3+
import { getShareData } from '../../utils';
4+
5+
function getShareString() {
6+
const data = getShareData();
7+
return `${ data.title } \n${ data.url } \n${ data.text }`;
8+
}
9+
10+
function fallbackCopyTextToClipboard(text) {
11+
const textArea = document.createElement('textarea');
12+
textArea.value = text;
13+
textArea.style.position = 'fixed'; // avoid scrolling to bottom
14+
document.body.appendChild(textArea);
15+
textArea.focus();
16+
textArea.select();
17+
18+
try {
19+
document.execCommand('copy');
20+
} catch (err) {
21+
console.error('Unable to copy', err);
22+
}
23+
24+
document.body.removeChild(textArea);
25+
}
26+
27+
Template.share.helpers({
28+
29+
});
30+
31+
Template.share.events({
32+
'click [data-type="copy"]'() {
33+
if (!navigator.clipboard) {
34+
fallbackCopyTextToClipboard(getShareString());
35+
return;
36+
}
37+
navigator.clipboard.writeText(getShareString());
38+
},
39+
'click [data-type="print"]'() {
40+
self.print();
41+
},
42+
'click [data-type="email"]'() {
43+
const { title } = getShareData();
44+
window.open(`mailto:?subject=${ title }&body=${ getShareString() }`);
45+
},
46+
'click [data-type="sms"]'() {
47+
location.href = `sms:?&body=${ getShareString() }`;
48+
},
49+
50+
51+
'click [data-type="facebook"]'() {
52+
const { url } = getShareData();
53+
window.open(`https://www.facebook.com/sharer/sharer.php?u=${ encodeURIComponent(url) }`);
54+
},
55+
'click [data-type="whatsapp"]'() {
56+
window.open(`https://api.whatsapp.com/send?text=${ encodeURIComponent(getShareString()) }`);
57+
},
58+
'click [data-type="twitter"]'() {
59+
const { url } = getShareData();
60+
window.open(`http://twitter.com/share?text=${ getShareString() }&url=${ url }`);
61+
},
62+
'click [data-type="linkedin"]'() {
63+
const { title, url } = getShareData();
64+
window.open(`https://www.linkedin.com/shareArticle?mini=true&url=${ url }&title=${ title }&summary=${ getShareString() }&source=LinkedIn`);
65+
},
66+
'click [data-type="telegram"]'() {
67+
const { url } = getShareData();
68+
window.open(`https://telegram.me/share/msg?url=${ url }&text=${ getShareString() }`);
69+
},
70+
71+
});

app/ui-share/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './client/index';

app/ui-sidenav/client/sidebarHeader.js

+7
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ const toolbarButtons = (/* user */) => [{
191191
};
192192
}
193193

194+
const shareOption = {
195+
name: t('Share'),
196+
icon: 'share',
197+
type: 'share-action',
198+
};
199+
194200
const sortOption = {
195201
name: t('Sort'),
196202
icon: 'sort',
@@ -251,6 +257,7 @@ const toolbarButtons = (/* user */) => [{
251257
if (isMobile()) {
252258
config.columns[0].groups[0].items = config.columns[0].groups[0].items.concat([sortOption, directoryOption]);
253259
}
260+
config.columns[0].groups[0].items = config.columns[0].groups[0].items.concat([shareOption]);
254261
popover.open(config);
255262
},
256263
}];

app/ui-utils/client/lib/popover.js

+18
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { FlowRouter } from 'meteor/kadira:flow-router';
55
import { Template } from 'meteor/templating';
66
import _ from 'underscore';
77

8+
import { share, isShareAvailable } from '../../../utils';
89
import { hide, leave } from './ChannelActions';
910
import { messageBox } from './messageBox';
1011
import { MessageAction } from './MessageAction';
@@ -191,6 +192,23 @@ Template.popover.events({
191192
};
192193
popover.open(config);
193194
},
195+
'click [data-type="share-action"]'(e) {
196+
if (isShareAvailable()) {
197+
share();
198+
} else {
199+
popover.close();
200+
const options = [];
201+
const config = {
202+
template: 'share',
203+
currentTarget: e.target,
204+
data: {
205+
options,
206+
},
207+
offsetVertical: e.target.clientHeight + 10,
208+
};
209+
popover.open(config);
210+
}
211+
},
194212
'click [data-type="sidebar-item"]'(e, instance) {
195213
popover.close();
196214
const { rid, name, template } = instance.data.data;

app/utils/client/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ export { APIClient, mountArrayQueryParameters } from './lib/RestApiClient';
2121
export { canDeleteMessage } from './lib/canDeleteMessage';
2222
export { mime } from '../lib/mimeTypes';
2323
export { secondsToHHMMSS } from '../lib/timeConverter';
24+
export { share, isShareAvailable, getShareData } from './lib/share';
2425
export { isMobile } from './lib/isMobile';

app/utils/client/lib/share.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Meteor } from 'meteor/meteor';
2+
3+
import { settings } from '../../../settings';
4+
5+
6+
export const isShareAvailable = () => {
7+
if (navigator.share) { return true; }
8+
return false;
9+
};
10+
11+
export const getShareData = () => {
12+
const data = {};
13+
14+
const siteName = settings.get('Site_Name') || '';
15+
const siteURL = settings.get('Site_Url') || '';
16+
17+
data.url = document.location.href || siteURL;
18+
const path = new URL(data.url).pathname;
19+
const roomName = path.substring(path.lastIndexOf('/') + 1);
20+
21+
const templateText = `${ siteName } is open source team communication app.`;
22+
23+
data.title = `${ siteName }`;
24+
data.text = `${ templateText } Open this link to connect.`;
25+
26+
if (path.startsWith('/channel')) {
27+
data.title = `Join #${ roomName } on ${ siteName }`;
28+
data.text = `You are invited to channel #${ roomName } on ${ siteName }. ${ data.text }`;
29+
} else if (path.startsWith('/group')) {
30+
data.title = `Join #${ roomName } on ${ siteName }`;
31+
data.text = `You are invited to private group 🔒${ roomName } on ${ siteName }. ${ data.text }`;
32+
} else if (path.startsWith('/direct')) {
33+
data.title = `Chat with @${ roomName } on ${ siteName }`;
34+
} else {
35+
const user = Meteor.user();
36+
37+
data.title = `${ siteName }`;
38+
data.text = `${ templateText } Open this link and connect with me.`;
39+
data.url = new URL(document.location.href).origin;
40+
41+
if (data.url && user) {
42+
data.url = `${ data.url }/direct/${ user.username }`;
43+
}
44+
}
45+
46+
return data;
47+
};
48+
49+
export const share = () => {
50+
const data = getShareData();
51+
52+
if (navigator.share) {
53+
navigator.share(data)
54+
.then(() => console.log('Successfully shared'))
55+
.catch((error) => console.log('Error while sharing', error));
56+
} else {
57+
console.log('Share feature not available');
58+
}
59+
};

client/importPackages.js

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ import '../app/ui-login';
7878
import '../app/ui-master/client';
7979
import '../app/ui-message';
8080
import '../app/ui-sidenav';
81+
import '../app/ui-share';
8182
import '../app/ui-vrecord/client';
8283
import '../app/videobridge/client';
8384
import '../app/webdav/client';

0 commit comments

Comments
 (0)