[NEW] Experimental Game Center (externalComponents implementation) (#15123)

pull/16928/head^2
Douglas Gubert 6 years ago committed by GitHub
parent 2c729b64ca
commit 292a7c3b30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      app/api/server/v1/groups.js
  2. 51
      app/apps/assets/stylesheets/apps.css
  3. 58
      app/apps/client/RealAppsEngineUIHost.js
  4. 69
      app/apps/client/gameCenter/gameCenter.html
  5. 110
      app/apps/client/gameCenter/gameCenter.js
  6. 30
      app/apps/client/gameCenter/gameContainer.html
  7. 65
      app/apps/client/gameCenter/gameContainer.js
  8. 54
      app/apps/client/gameCenter/invitePlayers.html
  9. 219
      app/apps/client/gameCenter/invitePlayers.js
  10. 35
      app/apps/client/gameCenter/tabBar.js
  11. 5
      app/apps/client/index.js
  12. 11
      app/apps/client/orchestrator.js
  13. 6
      app/apps/server/bridges/listeners.js
  14. 26
      app/apps/server/communication/rest.js
  15. 16
      app/apps/server/orchestrator.js
  16. 3
      app/ui-flextab/client/flexTabBar.js
  17. 9
      app/ui-master/public/README.md
  18. 377
      app/ui-master/public/icons.svg
  19. 3
      app/ui-master/public/icons/game.svg
  20. 4
      app/ui-master/public/icons/omnichannel.svg
  21. 2
      app/ui-utils/client/index.js
  22. 4
      app/ui-utils/client/lib/TabBar.js
  23. 11
      package-lock.json
  24. 2
      package.json
  25. 5
      packages/rocketchat-i18n/i18n/en.i18n.json
  26. 3
      packages/rocketchat-i18n/i18n/pt-BR.i18n.json
  27. 5
      packages/rocketchat-i18n/i18n/zh.i18n.json
  28. 9
      private/public/icons.svg

@ -8,7 +8,7 @@ import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMes
import { API } from '../api';
// Returns the private group subscription IF found otherwise it will return the failure of why it didn't. Check the `statusCode` property
function findPrivateGroupByIdOrName({ params, userId, checkedArchived = true }) {
export function findPrivateGroupByIdOrName({ params, userId, checkedArchived = true }) {
if ((!params.roomId || !params.roomId.trim()) && (!params.roomName || !params.roomName.trim())) {
throw new Meteor.Error('error-room-param-not-provided', 'The parameter "roomId" or "roomName" is required');
}

@ -370,6 +370,57 @@
}
}
.rc-game {
&__list {
.rc-table-title {
width: 135px;
}
}
&__container {
height: calc(100% - 79px);
}
&__close {
position: absolute;
top: -30px;
right: -25px;
cursor: pointer;
color: #e9ebee;
font-size: 20px;
&:hover {
color: white;
}
}
&__main {
min-width: 400px;
height: 100%;
}
}
.rc-game-modal {
&__container {
margin: -14px -14px -18px;
}
&__main {
min-height: 730px;
}
}
.rc-icon.game-center__invite-players-icon.game-center__invite-players-icon--plus {
font-size: 18px;
&:hover {
color: #1d74f5;
}
}
@keyframes play90 {
0% {
right: -798px;

@ -0,0 +1,58 @@
import { Meteor } from 'meteor/meteor';
import { Session } from 'meteor/session';
import { AppsEngineUIHost } from '@rocket.chat/apps-engine/client/AppsEngineUIHost';
import { Rooms } from '../../models/client';
import { APIClient } from '../../utils/client';
import { getUserAvatarURL } from '../../utils/lib/getUserAvatarURL';
export class RealAppsEngineUIHost extends AppsEngineUIHost {
constructor() {
super();
this._baseURL = document.baseURI.slice(0, -1);
}
getUserAvatarUrl(username) {
const avatarUrl = getUserAvatarURL(username);
if (!avatarUrl.startsWith('http') && !avatarUrl.startsWith('data')) {
return `${ this._baseURL }${ avatarUrl }`;
}
return avatarUrl;
}
async getClientRoomInfo() {
const { name: slugifiedName, _id: id } = Rooms.findOne(Session.get('openedRoom'));
let cachedMembers = [];
try {
const { members } = await APIClient.get('v1/groups.members', { roomId: id });
cachedMembers = members.map(({ _id, username }) => ({
id: _id,
username,
avatarUrl: this.getUserAvatarUrl(username),
}));
} catch (error) {
console.warn(error);
}
return {
id,
slugifiedName,
members: cachedMembers,
};
}
async getClientUserInfo() {
const { username, _id } = Meteor.user();
return {
id: _id,
username,
avatarUrl: this.getUserAvatarUrl(username),
};
}
}

@ -0,0 +1,69 @@
<template name="GameCenter">
{{#table onScroll=onTableScroll onResize=onTableResize onSort=onTableSort}}
<tbody class="rc-game__list">
<thead>
<tr>
<th class="js-sort rc-table-td--medium" data-sort="name">
<div class="table-fake-th">{{_ "Name"}}</div>
</th>
<th class="rc-table-td">
<div class="table-fake-th">{{_ "Description"}} </div>
</th>
</tr>
</thead>
{{#each games}}
<tr class="rc-game-center__game" data-name="{{name}}">
<td>
<div class="rc-table-wrapper">
{{#if icon}}
<div class="rc-table-avatar" style="background-image:url({{icon}})"></div>
{{/if}}
<div class="rc-table-info">
<span class="rc-table-title">
{{name}}
</span>
</div>
</div>
</td>
<td>
<div class="rc-table-wrapper">
<div class="rc-table-info">
<span class="rc-table-title">
{{#if summary}}
{{summary}}
{{else}}
{{description}}
{{/if}}
</span>
{{#if summary}}
<span class="rc-table-subtitle">
{{description}}
</span>
{{/if}}
</div>
</div>
</td>
<td>
<div class="rc-table-wrapper">
<div class="rc-table-info">
<button class="rc-tooltip game-center__invite-players js-invite" aria-label="Invite Friends">
{{> icon block="game-center__invite-players-icon" icon="plus"}}
</button>
</div>
</div>
</td>
</tr>
{{/each}}
{{#if isLoading}}
<tr>
<td colspan="3" style="position: relative;">{{> loading}}</td>
</tr>
{{/if}}
</tbody>
{{/table}}
<div class="rc-user-info-container flex-nav animated{{#unless showGame}} animated-hidden{{/unless}}">
{{#if showGame}}
{{> GameContainer (gameContainerOptions) }}
{{/if}}
</div>
</template>

@ -0,0 +1,110 @@
import toastr from 'toastr';
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { modal } from '../../../ui-utils/client';
import { APIClient, t } from '../../../utils/client';
const getExternalComponents = async (instance) => {
try {
const { externalComponents } = await APIClient.get('apps/externalComponents');
instance.games.set(externalComponents);
} catch (e) {
toastr.error((e.xhr.responseJSON && e.xhr.responseJSON.error) || e.message);
}
instance.isLoading.set(false);
instance.ready.set(true);
};
const openGame = (gameManifestInfo) => {
const instance = Template.instance();
const { location = 'MODAL' } = gameManifestInfo;
if (location === 'CONTEXTUAL_BAR') {
instance.gameManifestInfo.set(gameManifestInfo);
} else if (location === 'MODAL') {
modal.open({
allowOutsideClick: false,
data: {
game: gameManifestInfo,
},
template: 'GameContainer',
type: 'rc-game',
});
}
};
Template.GameCenter.helpers({
isReady() {
if (Template.instance().ready != null) {
return Template.instance().ready.get();
}
return false;
},
games() {
return Template.instance().games.get();
},
isLoading() {
return Template.instance().isLoading.get();
},
onTableScroll() {
const instance = Template.instance();
if (instance.loading || instance.end.get()) {
return;
}
return function(currentTarget) {
if (currentTarget.offsetHeight + currentTarget.scrollTop >= currentTarget.scrollHeight - 100) {
return instance.page.set(instance.page.get() + 1);
}
};
},
showGame() {
return Template.instance().gameManifestInfo.get();
},
gameContainerOptions() {
const { gameManifestInfo, clearGameManifestInfo } = Template.instance();
return {
game: gameManifestInfo.get(),
showBackButton: true,
clearGameManifestInfo,
};
},
});
Template.GameCenter.onCreated(function() {
this.ready = new ReactiveVar(false);
this.games = new ReactiveVar([]);
this.isLoading = new ReactiveVar(true);
this.page = new ReactiveVar(0);
this.end = new ReactiveVar(false);
this.gameManifestInfo = new ReactiveVar(null);
this.clearGameManifestInfo = () => {
this.gameManifestInfo.set(null);
};
getExternalComponents(this);
});
Template.GameCenter.events({
'click .rc-game-center__game'() {
const gameManifestInfo = this;
openGame(gameManifestInfo);
},
'click .js-invite'(event) {
event.stopPropagation();
modal.open({
title: t('Invite You Friends to Join'),
content: 'InvitePlayers',
data: this,
confirmOnEnter: false,
showCancelButton: false,
showConfirmButton: false,
html: false,
});
},
});

@ -0,0 +1,30 @@
<template name="GameContainer">
{{#if isContextualBar}}
<header class="contextual-bar__header">
<div class="contextual-bar__header-data">
{{#if showBackButton}}
<button
class="rc-button rc-button--nude contextual-bar__header-back-btn js-back"
title="{{_ 'Back_to_Game_Center'}}"
>
<i class="icon-angle-left"></i>
</button>
{{/if}}
<img class="rc-table-avatar contextual-bar__header-icon" src="{{ game.icon }}">
<h1 class="contextual-bar__header-title">{{ game.name }}</h1>
</div>
<button class="contextual-bar__header-close js-close">
{{> icon block="contextual-bar__header-close-icon" icon="plus"}}
</button>
</header>
{{/if}}
{{#if isLoading}}
{{> loading}}
{{else}}
<div class="rc-game__container {{#if isModal}} rc-game-modal__container {{/if}}">
<div class="rc-game__close"></div>
<iframe class="rc-game__main {{#if isModal}} rc-game-modal__main {{/if}}" src="{{ game.url }}"></iframe>
</div>
{{/if}}
</template>

@ -0,0 +1,65 @@
import { Template } from 'meteor/templating';
import { modal } from '../../../ui-utils/client';
import { Apps } from '../orchestrator';
import { APIClient } from '../../../utils/client';
import './gameContainer.html';
const getExternalComponent = async () => {
const { data: { game: externalComponent } } = Template.instance();
const realAppClientUIHost = Apps.getUIHost();
const currentUser = await realAppClientUIHost.getClientUserInfo();
const currentRoom = await realAppClientUIHost.getClientRoomInfo();
externalComponent.state = {
currentUser,
currentRoom,
};
return externalComponent;
};
Template.GameContainer.helpers({
isContextualBar() {
const { data: { game } } = Template.instance();
const { location } = game;
return location === 'CONTEXTUAL_BAR';
},
isModal() {
const { data: { game } } = Template.instance();
const { location } = game;
return location === 'MODAL';
},
});
Template.GameContainer.events({
'click .rc-game__close'() {
modal.cancel();
},
'click .js-back'() {
const { data: { clearGameManifestInfo } } = Template.instance();
clearGameManifestInfo();
},
});
Template.GameContainer.onCreated(async () => {
const externalComponent = await getExternalComponent();
APIClient.post('apps/externalComponentEvent', {
event: 'IPostExternalComponentOpened',
externalComponent,
});
});
Template.GameContainer.onDestroyed(async () => {
const externalComponent = await getExternalComponent();
APIClient.post('apps/externalComponentEvent', {
event: 'IPostExternalComponentClosed',
externalComponent,
});
});

@ -0,0 +1,54 @@
<template name="InvitePlayers">
<section class="invite-players">
<div class="invite-players__wrapper">
<form id="invite-players" class="invite-players__content">
<div class="invite-players__inputs">
{{> SearchInvitePlayers
onClickTag=onClickTagUser
deleteLastItem=deleteLastItemUser
list=selectedUsers
onSelect=onSelectUser
collection='UserAndRoom'
endpoint='users.autocomplete'
field='username'
sort='username'
label="Invite_Users"
placeholder="Username_Placeholder"
name="users"
icon="at"
noMatchTemplate="userSearchEmpty"
templateItem="popupList_item_default"
modifier=userModifier
}}
</div>
<input form="invite-players" style="background-color: #1D74F5; float: right;" class="rc-button rc-button--right rc-button--primary js-invite-players" type="submit" data-button="create" value="Invite">
</form>
</div>
</section>
</template>
<template name="SearchInvitePlayers">
<div class="rc-input" id='search-{{name}}' {{disabled}}>
<label class="rc-input__label">
<div class="rc-input__title">{{_ label}}</div>
<div class="rc-input__wrapper">
{{# if icon}}
<div class="rc-input__icon">
{{> icon block="rc-input__icon-svg" icon=icon}}
</div>
{{/if}}
<div class="rc-tags{{# unless icon}} rc-tags--no-icon{{/unless}}">
{{#each item in list}} {{> tag item}} {{/each}}
<input type="text" id="{{name}}" class="rc-tags__input" placeholder="{{_ placeholder}}" name="{{name}}" autocomplete="off" {{disabled}} />
</div>
</div>
{{#with config}}
{{#if autocomplete 'isShowing'}}
{{> popupList data=config items=items ready=(autocomplete 'isLoaded')}}
{{/if}}
{{/with}}
</label>
<div class="rc-input__description">{{ description }}</div>
</div>
</template>

@ -0,0 +1,219 @@
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Blaze } from 'meteor/blaze';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import { AutoComplete } from '../../../meteor-autocomplete/client';
import { roomTypes } from '../../../utils/client';
import { ChatRoom } from '../../../models/client';
import { call, modal } from '../../../ui-utils/client';
import './invitePlayers.html';
Template.InvitePlayers.helpers({
onSelectUser() {
return Template.instance().onSelectUser;
},
selectedUsers() {
const myUsername = Meteor.user().username;
const { message } = this;
const users = Template.instance().selectedUsers.get().map((e) => e);
if (message) {
users.unshift(message.u);
}
return users.filter(({ username }) => myUsername !== username);
},
onClickTagUser() {
return Template.instance().onClickTagUser;
},
deleteLastItemUser() {
return Template.instance().deleteLastItemUser;
},
onClickTagRoom() {
return Template.instance().onClickTagRoom;
},
deleteLastItemRoom() {
return Template.instance().deleteLastItemRoom;
},
selectedRoom() {
return Template.instance().selectedRoom.get();
},
onSelectRoom() {
return Template.instance().onSelectRoom;
},
roomCollection() {
return ChatRoom;
},
roomSelector() {
return (expression) => ({ name: { $regex: `.*${ expression }.*` } });
},
roomModifier() {
return (filter, text = '') => {
const f = filter.get();
return `#${ f.length === 0 ? text : text.replace(new RegExp(filter.get()), (part) => `<strong>${ part }</strong>`) }`;
};
},
userModifier() {
return (filter, text = '') => {
const f = filter.get();
return `@${ f.length === 0 ? text : text.replace(new RegExp(filter.get()), (part) => `<strong>${ part }</strong>`) }`;
};
},
nameSuggestion() {
return Template.instance().discussionName.get();
},
});
Template.InvitePlayers.events({
async 'submit #invite-players, click .js-invite-players'(e, instance) {
e.preventDefault();
const { data: { name } } = instance;
const users = instance.selectedUsers.get().map(({ username }) => username);
const privateGroupName = `${ name.replace(/\s/g, '-') }-${ Random.id(10) }`;
try {
const result = await call('createPrivateGroup', privateGroupName, users);
roomTypes.openRouteLink(result.t, result);
// setTimeout ensures the message is only sent after the
// user has been redirected to the new room, preventing a
// weird bug that made the message appear as unsent until
// the screen gets refreshed
setTimeout(() => call('sendMessage', {
_id: Random.id(),
rid: result.rid,
msg: TAPi18n.__('Game_Center_Play_Game_Together', { name }),
}), 100);
modal.close();
} catch (err) {
console.warn(err);
}
},
});
Template.InvitePlayers.onCreated(function() {
this.selectedUsers = new ReactiveVar([]);
this.onSelectUser = ({ item: user }) => {
if (user.username === Meteor.user().username) {
return;
}
const users = this.selectedUsers.get();
if (!users.find((u) => user.username === u.username)) {
this.selectedUsers.set([...users, user]);
}
};
this.onClickTagUser = ({ username }) => {
this.selectedUsers.set(this.selectedUsers.get().filter((user) => user.username !== username));
};
this.deleteLastItemUser = () => {
const arr = this.selectedUsers.get();
arr.pop();
this.selectedUsers.set(arr);
};
});
Template.SearchInvitePlayers.helpers({
list() {
return this.list;
},
items() {
return Template.instance().ac.filteredList();
},
config() {
const { filter } = Template.instance();
const { noMatchTemplate, templateItem, modifier } = Template.instance().data;
return {
filter: filter.get(),
template_item: templateItem,
noMatchTemplate,
modifier(text) {
return modifier(filter, text);
},
};
},
autocomplete(key) {
const instance = Template.instance();
const param = instance.ac[key];
return typeof param === 'function' ? param.apply(instance.ac) : param;
},
});
Template.SearchInvitePlayers.events({
'input input'(e, t) {
const input = e.target;
const position = input.selectionEnd || input.selectionStart;
const { length } = input.value;
document.activeElement === input && e && /input/i.test(e.type) && (input.selectionEnd = position + input.value.length - length);
t.filter.set(input.value);
},
'click .rc-popup-list__item'(e, t) {
t.ac.onItemClick(this, e);
},
'keydown input'(e, t) {
const KEYCODE_BACKSPACE = 8;
const KEYCODE_DELETE = 46;
t.ac.onKeyDown(e);
if ([KEYCODE_BACKSPACE, KEYCODE_DELETE].includes(e.keyCode) && e.target.value === '') {
const { deleteLastItem } = t;
return deleteLastItem && deleteLastItem();
}
},
'keyup input'(e, t) {
t.ac.onKeyUp(e);
},
'focus input'(e, t) {
t.ac.onFocus(e);
},
'blur input'(e, t) {
t.ac.onBlur(e);
},
'click .rc-tags__tag'({ target }, t) {
const { onClickTag } = t;
return onClickTag & onClickTag(Blaze.getData(target));
},
});
Template.SearchInvitePlayers.onRendered(function() {
const { name } = this.data;
this.ac.element = this.firstNode.querySelector(`[name=${ name }]`);
this.ac.$element = $(this.ac.element);
});
Template.SearchInvitePlayers.onCreated(function() {
this.filter = new ReactiveVar('');
this.selected = new ReactiveVar([]);
this.onClickTag = this.data.onClickTag;
this.deleteLastItem = this.data.deleteLastItem;
const { collection, endpoint, field, sort, onSelect, selector = (match) => ({ term: match }) } = this.data;
this.ac = new AutoComplete(
{
selector: {
anchor: '.rc-input__label',
item: '.rc-popup-list__item',
container: '.rc-popup-list__list',
},
onSelect,
position: 'fixed',
limit: 10,
inputDelay: 300,
rules: [
{
collection,
endpoint,
field,
matchAll: true,
doNotChangeWidth: false,
selector,
sort,
},
],
});
this.ac.tmplInst = this;
});

@ -0,0 +1,35 @@
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { APIClient } from '../../../utils/client';
import { TabBar, TABBAR_DEFAULT_VISIBLE_ICON_COUNT } from '../../../ui-utils/client';
import { settings } from '../../../settings/client';
import './gameCenter.html';
Meteor.startup(function() {
Tracker.autorun(async function() {
if (!settings.get('Apps_Game_Center_enabled')) {
TabBar.size = TABBAR_DEFAULT_VISIBLE_ICON_COUNT;
return TabBar.removeButton('gameCenter');
}
const { externalComponents } = await APIClient.get('apps/externalComponents');
if (!externalComponents.length) {
TabBar.size = TABBAR_DEFAULT_VISIBLE_ICON_COUNT;
return TabBar.removeButton('gameCenter');
}
TabBar.size = TABBAR_DEFAULT_VISIBLE_ICON_COUNT + 1;
TabBar.addButton({
groups: ['channel', 'group', 'direct'],
id: 'gameCenter',
i18nTitle: 'Game_Center',
icon: 'game',
template: 'GameCenter',
order: -1,
});
});
});

@ -1,3 +1,8 @@
import './routes';
import './gameCenter/tabBar';
import './gameCenter/gameContainer';
import './gameCenter/gameCenter';
import './gameCenter/invitePlayers';
export { Apps } from './orchestrator';

@ -1,4 +1,5 @@
import { Meteor } from 'meteor/meteor';
import { AppClientManager } from '@rocket.chat/apps-engine/client/AppClientManager';
import toastr from 'toastr';
import { AppWebsocketReceiver } from './communication';
@ -7,6 +8,7 @@ import { AdminBox } from '../../ui-utils';
import { CachedCollectionManager } from '../../ui-cached-collection';
import { hasAtLeastOnePermission } from '../../authorization';
import { handleI18nResources } from './i18n';
import { RealAppsEngineUIHost } from './RealAppsEngineUIHost';
const createDeferredValue = () => {
let resolve;
@ -21,6 +23,8 @@ const createDeferredValue = () => {
class AppClientOrchestrator {
constructor() {
this._appClientUIHost = new RealAppsEngineUIHost();
this._manager = new AppClientManager(this._appClientUIHost);
this.isLoaded = false;
[this.deferredIsEnabled, this.setEnabled] = createDeferredValue();
}
@ -42,7 +46,9 @@ class AppClientOrchestrator {
this.setEnabled(isEnabled);
}
getWsListener = () => this.ws
getWsListener = () => this.ws;
getAppClientManager = () => this._manager;
registerAdminMenuItems = () => {
AdminBox.addOption({
@ -179,6 +185,8 @@ class AppClientOrchestrator {
const categories = await APIClient.get('apps', { categories: 'true' });
return categories;
}
getUIHost = () => this._appClientUIHost;
}
export const Apps = new AppClientOrchestrator();
@ -191,6 +199,7 @@ Meteor.startup(() => {
return;
}
Apps.getAppClientManager().initialize();
Apps.load(isEnabled);
});
});

@ -37,6 +37,12 @@ export class AppListenerBridge {
// }
}
async externalComponentEvent(inte, externalComponent) {
const result = await this.orch.getManager().getListenerManager().executeListener(inte, externalComponent);
return result;
}
async uiKitInteractionEvent(inte, action) {
return this.orch.getManager().getListenerManager().executeListener(inte, action);

@ -257,6 +257,14 @@ export class AppsRestApi {
},
});
this.api.addRoute('externalComponents', { authRequired: false }, {
get() {
const externalComponents = orchestrator.getProvidedComponents();
return API.v1.success({ externalComponents });
},
});
this.api.addRoute('languages', { authRequired: false }, {
get() {
const apps = manager.get().map((prl) => ({
@ -268,6 +276,24 @@ export class AppsRestApi {
},
});
this.api.addRoute('externalComponentEvent', { authRequired: true }, {
post() {
if (!this.bodyParams.externalComponent || !['IPostExternalComponentOpened', 'IPostExternalComponentClosed'].includes(this.bodyParams.event)) {
return API.v1.failure({ error: 'Event and externalComponent must be provided.' });
}
try {
const { event, externalComponent } = this.bodyParams;
const result = Apps.getBridges().getListenerBridge().externalComponentEvent(event, externalComponent);
return API.v1.success({ result });
} catch (e) {
orchestrator.getRocketChatLogger().error(`Error triggering external components' events ${ e.response.data }`);
return API.v1.internalError();
}
},
});
this.api.addRoute('bundles/:id/apps', { authRequired: true, permissionsRequired: ['manage-apps'] }, {
get() {
const baseUrl = orchestrator.getMarketplaceUrl();

@ -88,6 +88,10 @@ class AppServerOrchestrator {
return this._manager;
}
getProvidedComponents() {
return this._manager.getExternalComponentManager().getProvidedComponents();
}
isInitialized() {
return this._isInitialized;
}
@ -171,9 +175,21 @@ settings.addGroup('General', function() {
public: true,
hidden: false,
});
this.add('Apps_Game_Center_enabled', false, {
type: 'boolean',
enableQuery: {
_id: 'Apps_Framework_enabled',
value: true,
},
hidden: false,
public: true,
alert: 'Experimental_Feature_Alert',
});
});
});
settings.get('Apps_Framework_enabled', (key, isEnabled) => {
// In case this gets called before `Meteor.startup`
if (!Apps.isInitialized()) {

@ -59,6 +59,9 @@ const filterButtons = (button, anonymous, rid) => {
if (button.id === 'thread' && !settings.get('Threads_enabled')) {
return false;
}
if (button.id === 'gameCenter' && !settings.get('Apps_Game_Center_enabled')) {
return false;
}
return true;
};
Template.flexTabBar.helpers({

@ -6,12 +6,5 @@ run below commands inside `app/ui-master/public` directory
```js
node generateSprite.js
node generateHTML.js
cp icons.svg ../../../private/public
```
After that 2 new files named `icons.html` and `icons.svg` will be generated. You need to cut and replace these two files to following locations.
- icons.html to `public/public/icons.html`
- icons.svg to `private/public/icons.svg`

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 206 KiB

@ -0,0 +1,3 @@
<svg id="game" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 20C15.5229 20 20 15.5228 20 10C20 4.47715 15.5229 0 10 0C4.47716 0 7.62939e-06 4.47715 7.62939e-06 10C7.62939e-06 15.5228 4.47716 20 10 20ZM16.3276 14.8957C17.203 13.7658 17.7825 12.3952 17.9499 10.9H14.9439C15.0872 12.3612 15.5759 13.7203 16.3276 14.8957ZM15.042 16.2115C13.8851 17.1517 12.4604 17.7752 10.9 17.9499V10.9H13.1367C13.2973 12.8635 13.9787 14.6807 15.042 16.2115ZM14.9439 9.1H17.9499C17.7825 7.60479 17.203 6.23416 16.3276 5.10434C15.5759 6.27969 15.0872 7.63879 14.9439 9.1ZM15.042 3.7885C13.9787 5.31935 13.2973 7.13646 13.1367 9.1H10.9V2.05006C12.4604 2.22475 13.8851 2.84826 15.042 3.7885ZM9.10001 17.9499C7.53945 17.7752 6.1146 17.1516 4.9576 16.2111C6.02095 14.6803 6.70261 12.8633 6.86331 10.9H9.10001V17.9499ZM5.05607 10.9C4.91267 12.3612 4.42373 13.72 3.67202 14.8952C2.79682 13.7654 2.21744 12.395 2.05007 10.9H5.05607ZM9.10001 9.1H6.86333C6.70272 7.13674 6.02142 5.31947 4.95804 3.7885C6.11496 2.84826 7.53965 2.22475 9.10001 2.05006V9.1ZM5.0561 9.1C4.91278 7.63858 4.42402 6.2796 3.67238 5.10437C2.79698 6.23418 2.21747 7.6048 2.05007 9.1H5.0561Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -1,3 +1,3 @@
<svg id="livechat" viewBox="0 0 20 20">
<svg id="omnichannel" viewBox="0 0 20 20">
<path d="M16.628,10.954 C16.628,11.33 16.32,11.637 15.942,11.637 C15.565,11.637 15.257,11.33 15.257,10.954 L15.257,9.137 C15.257,8.761 15.565,8.454 15.942,8.454 C16.32,8.454 16.628,8.761 16.628,9.137 L16.628,10.954 Z M10.228,16.637 L9.771,16.637 C9.393,16.637 9.086,16.33 9.086,15.954 C9.086,15.578 9.393,15.272 9.771,15.272 L10.228,15.272 C10.607,15.272 10.914,15.578 10.914,15.954 C10.914,16.33 10.607,16.637 10.228,16.637 Z M4.057,11.637 C3.679,11.637 3.371,11.33 3.371,10.954 L3.371,9.137 C3.371,8.761 3.679,8.454 4.057,8.454 C4.435,8.454 4.742,8.761 4.742,9.137 L4.742,10.954 C4.742,11.33 4.435,11.637 4.057,11.637 Z M15.942,7.091 C15.662,7.091 15.396,7.147 15.152,7.249 C14.667,4.828 12.542,3 10,3 C7.458,3 5.333,4.828 4.847,7.249 C4.604,7.147 4.337,7.091 4.057,7.091 C2.922,7.091 2,8.009 2,9.137 L2,10.954 C2,12.082 2.922,13 4.057,13 C5.151,13 6.04,12.144 6.102,11.071 L6.114,11.071 L6.114,10.954 L6.114,9.137 L6.114,8.301 C6.114,6.13 7.857,4.363 10,4.363 C12.142,4.363 13.885,6.13 13.885,8.301 L13.885,9.137 L13.885,10.954 L13.885,11.995 C13.885,13.345 13.218,14.55 12.156,15.265 C11.87,14.476 11.118,13.909 10.228,13.909 L9.771,13.909 C8.637,13.909 7.714,14.826 7.714,15.954 C7.714,17.082 8.637,18 9.771,18 L10.228,18 C11.029,18 11.717,17.538 12.057,16.872 C13.729,16.159 14.902,14.645 15.189,12.853 C15.423,12.945 15.676,13 15.942,13 C17.077,13 18,12.082 18,10.954 L18,9.137 C18,8.009 17.077,7.091 15.942,7.091 Z"/>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -17,7 +17,7 @@ export { Layout } from './lib/Layout';
export { IframeLogin, iframeLogin } from './lib/IframeLogin';
export { fireGlobalEvent } from './lib/fireGlobalEvent';
export { getAvatarAsPng, updateAvatarOfUsername } from './lib/avatar';
export { TabBar } from './lib/TabBar';
export { TabBar, TABBAR_DEFAULT_VISIBLE_ICON_COUNT } from './lib/TabBar';
export { RocketChatTabBar } from './lib/RocketChatTabBar';
export { popout } from './lib/popout';
export { messageProperties } from '../lib/MessageProperties';

@ -1,6 +1,8 @@
import _ from 'underscore';
import { ReactiveVar } from 'meteor/reactive-var';
export const TABBAR_DEFAULT_VISIBLE_ICON_COUNT = 4;
export const TabBar = new class TabBar {
get size() {
return this._size.get();
@ -12,7 +14,7 @@ export const TabBar = new class TabBar {
constructor() {
this.buttons = new ReactiveVar({});
this._size = new ReactiveVar(4);
this._size = new ReactiveVar(TABBAR_DEFAULT_VISIBLE_ICON_COUNT);
this.extraGroups = {};
}

11
package-lock.json generated

@ -2681,9 +2681,9 @@
}
},
"@rocket.chat/apps-engine": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.12.0.tgz",
"integrity": "sha512-HqhUQIisnMdx9X/ZnQh71dyxL+NLKtMjCyf7qoPmKs/MzMJ2a/Ix4AjSL5SRajM3SGlB1+cZ5/+vVZNeXOe68g==",
"version": "1.13.0-beta.2857",
"resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.13.0-beta.2857.tgz",
"integrity": "sha512-zWOmvGv1p1sj7s4aJAoPWIJ9Mmuz7Hlq3BKQYNh8ELjM1IiRXd1dwuyl+5q1hBuru+QZ7T7QZ+qCOa2OcM8tfQ==",
"requires": {
"adm-zip": "^0.4.9",
"cryptiles": "^4.1.3",
@ -2694,11 +2694,6 @@
"uuid": "^3.2.1"
},
"dependencies": {
"adm-zip": {
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz",
"integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g=="
},
"typescript": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",

@ -124,7 +124,7 @@
"@google-cloud/language": "^3.7.0",
"@google-cloud/storage": "^2.3.1",
"@google-cloud/vision": "^1.8.0",
"@rocket.chat/apps-engine": "^1.12.0",
"@rocket.chat/apps-engine": "^1.13.0-beta.2857",
"@rocket.chat/fuselage": "^0.3.0",
"@rocket.chat/fuselage-hooks": "^0.3.0",
"@rocket.chat/fuselage-ui-kit": "^0.3.0",

@ -385,6 +385,7 @@
"Apps_Framework_Development_Mode": "Enable development mode",
"Apps_Framework_Development_Mode_Description": "Development mode allows the installation of Apps that are not from the Rocket.Chat's Marketplace.",
"Apps_Framework_enabled": "Enable the App Framework",
"Apps_Game_Center_enabled": "Enable the Game Center",
"Apps_Marketplace_Deactivate_App_Prompt": "Do you really want to disable this app?",
"Apps_Marketplace_Modify_App_Subscription": "Modify Subscription",
"Apps_Marketplace_Uninstall_App_Prompt": "Do you really want to uninstall this app?",
@ -487,6 +488,7 @@
"Back": "Back",
"Back_to_applications": "Back to applications",
"Back_to_chat": "Back to chat",
"Back_to_Game_Center": "Back to Game Center",
"Back_to_imports": "Back to imports",
"Back_to_integration_detail": "Back to the integration detail",
"Back_to_integrations": "Back to integrations",
@ -1436,6 +1438,7 @@
"except_pinned": "(except those that are pinned)",
"Execute_Synchronization_Now": "Execute Synchronization Now",
"Exit_Full_Screen": "Exit Full Screen",
"Experimental_Feature_Alert": "This is an experimental feature! Please be aware that it may change, break, or even be removed in the future without any notice.",
"Expiration": "Expiration",
"Expiration_(Days)": "Expiration (Days)",
"Export_My_Data": "Export My Data (JSON)",
@ -1595,6 +1598,8 @@
"From_Email": "From Email",
"From_email_warning": "<b>Warning</b>: The field <b>From</b> is subject to your mail server settings.",
"Full_Screen": "Full Screen",
"Game_Center": "Game Center",
"Game_Center_Play_Game_Together": "@here Let's play __name__ together!",
"Gaming": "Gaming",
"General": "General",
"Get_link": "Get Link",

@ -370,6 +370,7 @@
"Apps_Engine_Version": "Versão da Apps Engine",
"Apps_Framework_Development_Mode": "Habilitar modo de desenvolvimento",
"Apps_Framework_enabled": "Ativar o App Framework",
"Apps_Game_Center_enabled": "Habilitar Game Center",
"Apps_Settings": "Configurações da aplicação",
"Apps_WhatIsIt": "Apps: o que são eles?",
"Apps_WhatIsIt_paragraph1": "Um novo ícone na área de administração! O que significa e quais são as aplicações?",
@ -1335,6 +1336,7 @@
"except_pinned": "(exceto aqueles que estão presos)",
"Execute_Synchronization_Now": "Execute sincronização agora",
"Exit_Full_Screen": "Sair da tela cheia",
"Experimental_Feature_Alert": "Esta é uma funcionalidade experimental! Essas funcionalidades podem sofrer mudanças, parar de funcionar, ou até serem removidas sem aviso prévio.",
"Expiration": "Validade",
"Expiration_(Days)": "Validade (Dias)",
"Export_My_Data": "Exportar meus dados (JSON)",
@ -1472,6 +1474,7 @@
"From_Email": "Email De",
"From_email_warning": "<b>Aviso</b>: O campo <b>De</b> está sujeito às configurações do seu servidor de emails.",
"Full_Screen": "Tela cheia",
"Game_Center": "Game Center",
"Gaming": "Jogos",
"General": "Geral",
"Get_link": "Obter Link",

@ -374,6 +374,7 @@
"Apps_Framework_Development_Mode": "启用开发模式",
"Apps_Framework_Development_Mode_Description": "开发模式允许您安装那些不在 Rocket.Chat 市场中的应用。",
"Apps_Framework_enabled": "启用应用框架",
"Apps_Game_Center_enabled": "启用游戏中心",
"Apps_Marketplace_Deactivate_App_Prompt": "是否确定要禁用此应用程序?",
"Apps_Marketplace_Modify_App_Subscription": "修改订阅",
"Apps_Marketplace_Uninstall_App_Prompt": "是否确定要卸载此应用程序?",
@ -1401,6 +1402,7 @@
"except_pinned": "(固定的除外)",
"Execute_Synchronization_Now": "立即执行同步",
"Exit_Full_Screen": "退出全屏",
"Experimental_Feature_Alert": "这是一个实验性特性!请注意这个特性随时都会改变、损坏甚至在未来版本中不加任何通知地被移除。",
"Expiration": "期满",
"Expiration_(Days)": "到期天数",
"Export_My_Data": "导出我的数据",
@ -1549,6 +1551,7 @@
"From_Email": "从电子邮件",
"From_email_warning": "<b>警告</b>:<b>From</b> 字段来自于邮件服务器的设置。",
"Full_Screen": "全屏",
"Game_Center": "游戏中心",
"Gaming": "游戏",
"General": "通用",
"Get_link": "获取链接",
@ -3547,4 +3550,4 @@
"Your_server_link": "您的服务器链接",
"Your_temporary_password_is_password": "您的暂时密码为 <strong>[password]</strong>。",
"Your_workspace_is_ready": "您的工作区已准备好使用🎉"
}
}

@ -146,6 +146,9 @@
<symbol id="icon-folder" viewBox="0 0 20 20" fill="currentColor">
<path d="M7.325376,4.5 L4,4.5 C3.72385763,4.5 3.5,4.72385763 3.5,5 L3.5,15 C3.5,15.2761424 3.72385763,15.5 4,15.5 L16,15.5 C16.2761424,15.5 16.5,15.2761424 16.5,15 L16.5,7 C16.5,6.72385763 16.2761424,6.5 16,6.5 L9.316214,6.5 L7.700244,4.66913179 C7.60533058,4.56159644 7.46880685,4.5 7.325376,4.5 Z M9.992979,5 L17,5 C17.5522847,5 18,5.44771525 18,6 L18,16 C18,16.5522847 17.5522847,17 17,17 L3,17 C2.44771525,17 2,16.5522847 2,16 L2,4 C2,3.44771525 2.44771525,3 3,3 L7.776552,3 C8.0634137,3 8.33646216,3.12319287 8.526289,3.33826358 L9.992979,5 Z"/>
</symbol>
<symbol id="icon-game" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 20C15.5229 20 20 15.5228 20 10C20 4.47715 15.5229 0 10 0C4.47716 0 7.62939e-06 4.47715 7.62939e-06 10C7.62939e-06 15.5228 4.47716 20 10 20ZM16.3276 14.8957C17.203 13.7658 17.7825 12.3952 17.9499 10.9H14.9439C15.0872 12.3612 15.5759 13.7203 16.3276 14.8957ZM15.042 16.2115C13.8851 17.1517 12.4604 17.7752 10.9 17.9499V10.9H13.1367C13.2973 12.8635 13.9787 14.6807 15.042 16.2115ZM14.9439 9.1H17.9499C17.7825 7.60479 17.203 6.23416 16.3276 5.10434C15.5759 6.27969 15.0872 7.63879 14.9439 9.1ZM15.042 3.7885C13.9787 5.31935 13.2973 7.13646 13.1367 9.1H10.9V2.05006C12.4604 2.22475 13.8851 2.84826 15.042 3.7885ZM9.10001 17.9499C7.53945 17.7752 6.1146 17.1516 4.9576 16.2111C6.02095 14.6803 6.70261 12.8633 6.86331 10.9H9.10001V17.9499ZM5.05607 10.9C4.91267 12.3612 4.42373 13.72 3.67202 14.8952C2.79682 13.7654 2.21744 12.395 2.05007 10.9H5.05607ZM9.10001 9.1H6.86333C6.70272 7.13674 6.02142 5.31947 4.95804 3.7885C6.11496 2.84826 7.53965 2.22475 9.10001 2.05006V9.1ZM5.0561 9.1C4.91278 7.63858 4.42402 6.2796 3.67238 5.10437C2.79698 6.23418 2.21747 7.6048 2.05007 9.1H5.0561Z"/>
</symbol>
<symbol id="icon-github" viewBox="0 0 20 20" fill="currentColor">
<path d="M7.26894971,14.8834111 C7.26894971,14.9490684 7.19284523,15.001959 7.09565157,15.001959 C6.98562101,15.0119899 6.90951653,14.9590994 6.90951653,14.8834111 C6.90951653,14.816842 6.98653793,14.7648633 7.08281467,14.7648633 C7.1827591,14.7539205 7.26894971,14.806811 7.26894971,14.8834111 Z M6.23466241,14.7347704 C6.21082245,14.8004277 6.27775771,14.8770278 6.37770214,14.8961778 C6.46389275,14.9299184 6.56383718,14.8961778 6.58400945,14.8305206 C6.6032648,14.7639514 6.53999722,14.6882632 6.44096971,14.6581703 C6.35386218,14.6353727 6.25758544,14.6682013 6.23466241,14.7347704 Z M7.70448736,14.6782322 C7.60821061,14.7010299 7.54219228,14.7639514 7.55136149,14.8405516 C7.56144762,14.9062088 7.64855515,14.9499803 7.74758266,14.9262707 C7.84477633,14.9034731 7.91079467,14.8405516 7.90070853,14.7739824 C7.89153932,14.7110609 7.80168102,14.6682013 7.70448736,14.6782322 Z M9.89409558,2 C5.27923034,2 1.75,5.48348178 1.75,10.0731058 C1.75,13.7417045 4.0716449,16.8813977 7.38906641,17.986628 C7.81451792,18.0623162 7.9639761,17.8015111 7.9639761,17.5863012 C7.9639761,17.3811223 7.95480689,16.2494467 7.95480689,15.5545741 C7.95480689,15.5545741 5.62582662,16.051563 5.13619061,14.5697154 C5.13619061,14.5697154 4.75750208,13.6058305 4.21193387,13.357792 C4.21193387,13.357792 3.44997221,12.8380055 4.26511531,12.8489484 C4.26511531,12.8489484 5.0930953,12.9146056 5.54880522,13.7024926 C6.27775771,14.9791613 7.49818005,14.6116631 7.97406224,14.3937175 C8.05108363,13.8648119 8.26747708,13.4973137 8.50587663,13.2784562 C6.64727702,13.0732773 4.77033898,12.8051769 4.77033898,9.62262413 C4.77033898,8.71254172 5.02340928,8.25658861 5.55614059,7.67388053 C5.46903306,7.45867066 5.18662128,6.57229781 5.6423312,5.4278555 C6.3373576,5.21264563 7.93738538,6.3215236 7.93738538,6.3215236 C8.61789979,6.13383695 9.32085186,6.03874118 10.0270492,6.03883267 C10.7329655,6.0384409 11.4356553,6.13354292 12.1157961,6.3215236 C12.1157961,6.3215236 13.7158238,5.208998 14.4117672,5.4278555 C14.8674771,6.57594544 14.5841484,7.45867066 14.4979578,7.67388053 C15.0297722,8.25932433 15.3561962,8.71618935 15.3561962,9.62262413 C15.3561962,12.8152078 13.3967352,13.0696297 11.5372187,13.2793681 C11.8434704,13.5401733 12.1029592,14.0362503 12.1029592,14.8141063 C12.1029592,15.9284557 12.092873,17.3081698 12.092873,17.5799178 C12.092873,17.7951277 12.2459989,18.0559329 12.6677827,17.9802447 C15.9952904,16.8813977 18.25,13.7417045 18.25,10.0731058 C18.25,5.48348178 14.5080439,2 9.89409558,2 Z M4.98398166,13.4106826 C4.93996944,13.4444231 4.95005557,13.5201113 5.0069047,13.5830329 C5.06008614,13.6359234 5.13619061,13.6587211 5.18020283,13.6158615 C5.22329814,13.5830329 5.213212,13.5064327 5.15636288,13.4444231 C5.10318144,13.3915326 5.02707697,13.367823 4.98398166,13.4106826 Z M4.62454849,13.1425822 C4.60070853,13.1863537 4.6337177,13.2392442 4.70065296,13.2720728 C4.7538344,13.3049015 4.81985274,13.2948705 4.84369269,13.2492752 C4.86753265,13.2055037 4.83452348,13.1526131 4.76758822,13.1197845 C4.70065296,13.0997226 4.64838844,13.1106654 4.62454849,13.1425822 Z M5.70193109,14.320765 C5.64874965,14.3636246 5.66892192,14.4630224 5.7450264,14.5259439 C5.82204779,14.6016321 5.91832453,14.6116631 5.96141984,14.5587725 C6.00451514,14.5159129 5.98525979,14.4165152 5.91832453,14.3535936 C5.84497083,14.2779054 5.7450264,14.2678744 5.70193109,14.320765 Z M5.32324257,13.834719 C5.27006113,13.8675476 5.27006113,13.9532668 5.32324257,14.0298669 C5.37642401,14.1055551 5.4662823,14.1392957 5.5093776,14.1055551 C5.56255904,14.0626955 5.56255904,13.9769764 5.5093776,13.9003762 C5.46261462,13.824688 5.37642401,13.7909475 5.32324257,13.834719 Z"/>
</symbol>
@ -197,9 +200,6 @@
<symbol id="icon-list" viewBox="0 0 20 20" fill="currentColor">
<path d="M6.7826087,5.75 C6.35038585,5.75 6,5.41421356 6,5 C6,4.58578644 6.35038585,4.25 6.7826087,4.25 L17.2173913,4.25 C17.6496142,4.25 18,4.58578644 18,5 C18,5.41421356 17.6496142,5.75 17.2173913,5.75 L6.7826087,5.75 Z M6.7826087,10.75 C6.35038585,10.75 6,10.4142136 6,10 C6,9.58578644 6.35038585,9.25 6.7826087,9.25 L17.2173913,9.25 C17.6496142,9.25 18,9.58578644 18,10 C18,10.4142136 17.6496142,10.75 17.2173913,10.75 L6.7826087,10.75 Z M6.7826087,15.75 C6.35038585,15.75 6,15.4142136 6,15 C6,14.5857864 6.35038585,14.25 6.7826087,14.25 L17.2173913,14.25 C17.6496142,14.25 18,14.5857864 18,15 C18,15.4142136 17.6496142,15.75 17.2173913,15.75 L6.7826087,15.75 Z M1.995652,15 L1.995652,15 C1.995652,14.5857864 2.33143844,14.25 2.745652,14.25 L3.85434765,14.25 C4.26856121,14.25 4.60434765,14.5857864 4.60434765,15 L4.60434765,15 C4.60434765,15.4142136 4.26856121,15.75 3.85434765,15.75 L2.745652,15.75 C2.33143844,15.75 1.995652,15.4142136 1.995652,15 Z M1.995652,10 L1.995652,10 C1.995652,9.58578644 2.33143844,9.25 2.745652,9.25 L3.85434765,9.25 C4.26856121,9.25 4.60434765,9.58578644 4.60434765,10 L4.60434765,10 C4.60434765,10.4142136 4.26856121,10.75 3.85434765,10.75 L2.745652,10.75 C2.33143844,10.75 1.995652,10.4142136 1.995652,10 Z M1.995652,5 L1.995652,5 C1.995652,4.58578644 2.33143844,4.25 2.745652,4.25 L3.85434765,4.25 C4.26856121,4.25 4.60434765,4.58578644 4.60434765,5 L4.60434765,5 C4.60434765,5.41421356 4.26856121,5.75 3.85434765,5.75 L2.745652,5.75 C2.33143844,5.75 1.995652,5.41421356 1.995652,5 Z"/>
</symbol>
<symbol id="icon-omnichannel" viewBox="0 0 20 20" fill="currentColor">
<path d="M16.628,10.954 C16.628,11.33 16.32,11.637 15.942,11.637 C15.565,11.637 15.257,11.33 15.257,10.954 L15.257,9.137 C15.257,8.761 15.565,8.454 15.942,8.454 C16.32,8.454 16.628,8.761 16.628,9.137 L16.628,10.954 Z M10.228,16.637 L9.771,16.637 C9.393,16.637 9.086,16.33 9.086,15.954 C9.086,15.578 9.393,15.272 9.771,15.272 L10.228,15.272 C10.607,15.272 10.914,15.578 10.914,15.954 C10.914,16.33 10.607,16.637 10.228,16.637 Z M4.057,11.637 C3.679,11.637 3.371,11.33 3.371,10.954 L3.371,9.137 C3.371,8.761 3.679,8.454 4.057,8.454 C4.435,8.454 4.742,8.761 4.742,9.137 L4.742,10.954 C4.742,11.33 4.435,11.637 4.057,11.637 Z M15.942,7.091 C15.662,7.091 15.396,7.147 15.152,7.249 C14.667,4.828 12.542,3 10,3 C7.458,3 5.333,4.828 4.847,7.249 C4.604,7.147 4.337,7.091 4.057,7.091 C2.922,7.091 2,8.009 2,9.137 L2,10.954 C2,12.082 2.922,13 4.057,13 C5.151,13 6.04,12.144 6.102,11.071 L6.114,11.071 L6.114,10.954 L6.114,9.137 L6.114,8.301 C6.114,6.13 7.857,4.363 10,4.363 C12.142,4.363 13.885,6.13 13.885,8.301 L13.885,9.137 L13.885,10.954 L13.885,11.995 C13.885,13.345 13.218,14.55 12.156,15.265 C11.87,14.476 11.118,13.909 10.228,13.909 L9.771,13.909 C8.637,13.909 7.714,14.826 7.714,15.954 C7.714,17.082 8.637,18 9.771,18 L10.228,18 C11.029,18 11.717,17.538 12.057,16.872 C13.729,16.159 14.902,14.645 15.189,12.853 C15.423,12.945 15.676,13 15.942,13 C17.077,13 18,12.082 18,10.954 L18,9.137 C18,8.009 17.077,7.091 15.942,7.091 Z"/>
</symbol>
<symbol id="icon-loading" viewBox="0 0 20 20" fill="currentColor">
<path d="M10,2.68702533 L10,2.68702533 C10,3.06515396 9.71022961,3.38019545 9.333419,3.41173939 C9.20724273,3.42233281 9.10021136,3.43419215 9.01232745,3.44734802 C5.81995673,3.92523329 3.37142857,6.68414566 3.37142857,10.0159806 C3.37142857,13.3545008 5.82979236,16.117797 9.03155256,16.5874622 C9.11479793,16.5996735 9.21552923,16.6107219 9.33374646,16.6206074 L9.33374367,16.6206408 C9.7103617,16.6521342 10,16.9670034 10,17.3449359 L10,17.3449359 C10,17.7068101 9.70664301,18.0001671 9.34476882,18.0001671 C9.32883938,18.0001671 9.31291523,17.9995862 9.29702812,17.9984256 C9.18973641,17.9906119 9.09725269,17.9819371 9.01957518,17.9724256 C5.06413098,17.4880865 2,14.1109378 2,10.0159806 C2,5.93002254 5.05067833,2.5587214 8.99351071,2.06277065 C9.07782726,2.05216486 9.17917305,2.04254526 9.29754807,2.03391185 L9.29755023,2.03394136 C9.65823854,2.00763539 9.9719594,2.27870584 9.99826537,2.63939416 C9.99942141,2.6552449 10,2.67113248 10,2.68702533 Z"/>
</symbol>
@ -236,6 +236,9 @@
<symbol id="icon-mute" viewBox="0 0 20 20" fill="currentColor">
<path d="M8.07162956,9.03236085 L6.868093,10.0641379 C6.6325462,9.59341351 6.5,9.06218567 6.5,8.5 L6.5,5.5 C6.5,3.56700338 8.06700338,2 10,2 C11.5863668,2 12.9262329,3.05539481 13.3557571,4.50234323 L12,5.66461716 L12,5.5 C12,4.3954305 11.1045695,3.5 10,3.5 C8.8954305,3.5 8,4.3954305 8,5.5 L8,8.5 C8,8.684342 8.02493988,8.86285898 8.07162956,9.03236085 Z M7.37145588,14.2427133 L8.69338552,13.1094393 C9.08788589,13.2036768 9.52319165,13.25 10,13.25 C12.5473822,13.25 13.9101536,11.9277943 14.1946327,9.04074514 C14.2030058,8.95577013 14.2109047,8.85128998 14.2183292,8.72730468 L14.2183104,8.72730356 C14.2429945,8.31509415 14.5870831,7.99494551 15,8 C15.402301,8.00492454 15.7244382,8.33504606 15.7195137,8.73734705 C15.7193751,8.74867236 15.7189723,8.75999289 15.7183058,8.77129942 C15.7126924,8.86709227 15.7067695,8.95009551 15.7005706,9.02031109 C15.39585,12.4718915 13.7154723,14.4393939 10.75,14.716139 L10.75,17 L12.5,17 C12.7761424,17 13,17.2238576 13,17.5 C13,17.7761424 12.7761424,18 12.5,18 L7.5,18 C7.22385763,18 7,17.7761424 7,17.5 C7,17.2238576 7.22385763,17 7.5,17 L9.25,17 L9.25,14.716139 C8.55228772,14.6510268 7.92571318,14.4923209 7.37145588,14.2427133 Z M4.94084799,11.7163414 C4.60618286,10.9564611 4.39181379,10.0586727 4.30015364,9.02848274 C4.29372099,8.95618468 4.28758275,8.87041985 4.28173892,8.77118824 L4.28175695,8.77118718 C4.25810647,8.3695884 4.5644941,8.02485576 4.96609288,8.00120528 C4.97738436,8.00054032 4.9886898,8.00013845 5,8 C5.41277955,7.99494719 5.75675134,8.31499417 5.78141823,8.72706702 C5.78840657,8.84343937 5.79579487,8.94198439 5.80360528,9.02270073 C5.86440242,9.65100643 5.97602995,10.2055069 6.13957636,10.6886863 L4.94084799,11.7163414 Z M13.4613488,9.02192297 C13.2093532,10.7073691 11.7556316,12 10,12 C9.9958443,12 9.99169029,11.9999928 9.98753799,11.9999783 L13.4613488,9.02192297 Z M17.7972,2.9998 C18.0667928,3.31427187 18.0304112,3.7877499 17.7159393,4.05734277 L3.07474272,16.6090606 C2.76027085,16.8786535 2.28679282,16.8422719 2.01719995,16.5278 C1.74760708,16.2133281 1.7839887,15.7398501 2.09846057,15.4702572 L16.7396572,2.91853938 C17.0541291,2.64894651 17.5276071,2.68532813 17.7972,2.9998 Z"/>
</symbol>
<symbol id="icon-omnichannel" viewBox="0 0 20 20" fill="currentColor">
<path d="M16.628,10.954 C16.628,11.33 16.32,11.637 15.942,11.637 C15.565,11.637 15.257,11.33 15.257,10.954 L15.257,9.137 C15.257,8.761 15.565,8.454 15.942,8.454 C16.32,8.454 16.628,8.761 16.628,9.137 L16.628,10.954 Z M10.228,16.637 L9.771,16.637 C9.393,16.637 9.086,16.33 9.086,15.954 C9.086,15.578 9.393,15.272 9.771,15.272 L10.228,15.272 C10.607,15.272 10.914,15.578 10.914,15.954 C10.914,16.33 10.607,16.637 10.228,16.637 Z M4.057,11.637 C3.679,11.637 3.371,11.33 3.371,10.954 L3.371,9.137 C3.371,8.761 3.679,8.454 4.057,8.454 C4.435,8.454 4.742,8.761 4.742,9.137 L4.742,10.954 C4.742,11.33 4.435,11.637 4.057,11.637 Z M15.942,7.091 C15.662,7.091 15.396,7.147 15.152,7.249 C14.667,4.828 12.542,3 10,3 C7.458,3 5.333,4.828 4.847,7.249 C4.604,7.147 4.337,7.091 4.057,7.091 C2.922,7.091 2,8.009 2,9.137 L2,10.954 C2,12.082 2.922,13 4.057,13 C5.151,13 6.04,12.144 6.102,11.071 L6.114,11.071 L6.114,10.954 L6.114,9.137 L6.114,8.301 C6.114,6.13 7.857,4.363 10,4.363 C12.142,4.363 13.885,6.13 13.885,8.301 L13.885,9.137 L13.885,10.954 L13.885,11.995 C13.885,13.345 13.218,14.55 12.156,15.265 C11.87,14.476 11.118,13.909 10.228,13.909 L9.771,13.909 C8.637,13.909 7.714,14.826 7.714,15.954 C7.714,17.082 8.637,18 9.771,18 L10.228,18 C11.029,18 11.717,17.538 12.057,16.872 C13.729,16.159 14.902,14.645 15.189,12.853 C15.423,12.945 15.676,13 15.942,13 C17.077,13 18,12.082 18,10.954 L18,9.137 C18,8.009 17.077,7.091 15.942,7.091 Z"/>
</symbol>
<symbol id="icon-pause" viewBox="0 0 20 20" fill="currentColor">
<path d="M10,18 C5.58217143,18 2,14.4187429 2,10 C2,5.58125714 5.58217143,2 10,2 C14.4178286,2 18,5.58125714 18,10 C18,14.4187429 14.4178286,18 10,18 Z M11.0146065,7.74166381 L11.0020833,12.2500029 C11.0009359,12.6630659 11.3348595,12.9988497 11.7479225,12.9999971 C11.748615,12.999999 11.7493075,13 11.75,13 L11.75,13 C12.1642136,13 12.5,12.6642136 12.5,12.25 L12.5,7.74166667 C12.5,7.33205548 12.1679445,7 11.7583333,7 L11.7583333,7 C11.3483893,7 11.0157452,7.33172136 11.0146065,7.74166381 Z M7.5,7.75 L7.5,12.25 C7.5,12.6642136 7.83578644,13 8.25,13 L8.25,13 C8.66421356,13 9,12.6642136 9,12.25 L9,7.75 C9,7.33578644 8.66421356,7 8.25,7 L8.25,7 C7.83578644,7 7.5,7.33578644 7.5,7.75 Z"/>
</symbol>

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 206 KiB

Loading…
Cancel
Save