feat: Add an extended bubble design for the widget (#1123)

* feat: Add a new design for chat bubble

Signed-off-by: Pranav Raj Sreepuram <pranavrajs@gmail.com>

* Add i18n

* Fix stye issues

* Set fixed font-size

* Update docs for bubble
This commit is contained in:
Pranav Raj S 2020-08-09 16:07:32 +05:30 committed by GitHub
parent a04ca24def
commit 0adbc346df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 164 additions and 84 deletions

View file

@ -1,5 +1,6 @@
import Cookies from 'js-cookie';
import { IFrameHelper } from '../sdk/IFrameHelper';
import { getBubbleView } from '../sdk/bubbleHelpers';
const runSDK = ({ baseUrl, websiteToken }) => {
const chatwootSettings = window.chatwootSettings || {};
@ -11,6 +12,7 @@ const runSDK = ({ baseUrl, websiteToken }) => {
position: chatwootSettings.position === 'left' ? 'left' : 'right',
websiteToken,
locale: chatwootSettings.locale,
type: getBubbleView(chatwootSettings.type),
toggle() {
IFrameHelper.events.toggleBubble();

View file

@ -1,4 +1,4 @@
import { SDK_CSS } from '../widget/assets/scss/sdk';
import { SDK_CSS } from './sdk.js';
export const loadCSS = () => {
const css = document.createElement('style');

View file

@ -1,5 +1,5 @@
import Cookies from 'js-cookie';
import { wootOn, loadCSS, addClass, removeClass } from './DOMHelpers';
import { wootOn, addClass, loadCSS, removeClass } from './DOMHelpers';
import {
body,
widgetHolder,
@ -12,6 +12,7 @@ import {
createNotificationBubble,
onClickChatBubble,
onBubbleClick,
setBubbleText,
} from './bubbleHelpers';
import { dispatchWindowEvent } from 'shared/helpers/CustomEventHelper';
@ -32,8 +33,9 @@ export const IFrameHelper = {
iframe.id = 'chatwoot_live_chat_widget';
iframe.style.visibility = 'hidden';
const HolderclassName = `woot-widget-holder woot--hide woot-elements--${window.$chatwoot.position}`;
addClass(widgetHolder, HolderclassName);
const holderClassName = `woot-widget-holder woot--hide woot-elements--${window.$chatwoot.position}`;
addClass(widgetHolder, holderClassName);
widgetHolder.appendChild(iframe);
body.appendChild(widgetHolder);
IFrameHelper.initPostMessageCommunication();
@ -69,9 +71,7 @@ export const IFrameHelper = {
};
},
initWindowSizeListener: () => {
wootOn(window, 'resize', () => {
IFrameHelper.toggleCloseButton();
});
wootOn(window, 'resize', () => IFrameHelper.toggleCloseButton());
},
preventDefaultScroll: () => {
widgetHolder.addEventListener('wheel', event => {
@ -100,7 +100,9 @@ export const IFrameHelper = {
position: window.$chatwoot.position,
hideMessageBubble: window.$chatwoot.hideMessageBubble,
});
IFrameHelper.onLoad(message.config.channelConfig);
IFrameHelper.onLoad({
widgetColor: message.config.channelConfig.widgetColor,
});
IFrameHelper.setCurrentUrl();
IFrameHelper.toggleCloseButton();
@ -110,6 +112,10 @@ export const IFrameHelper = {
dispatchWindowEvent(EVENT_NAME);
},
setBubbleLabel(message) {
setBubbleText(message.label);
},
toggleBubble: () => {
onBubbleClick();
},

View file

@ -1,5 +1,6 @@
import { addClass, toggleClass, wootOn } from './DOMHelpers';
import { IFrameHelper } from './IFrameHelper';
import { BUBBLE_DESIGN } from './constants';
export const bubbleImg =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAUVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////8IN+deAAAAGnRSTlMAAwgJEBk0TVheY2R5eo+ut8jb5OXs8fX2+cjRDTIAAADsSURBVHgBldZbkoMgFIThRgQv8SKKgGf/C51UnJqaRI30/9zfe+NQUQ3TvG7bOk9DVeCmshmj/CuOTYnrdBfkUOg0zlOtl9OWVuEk4+QyZ3DIevmSt/ioTvK1VH/s5bY3YdM9SBZ/mUUyWgx+U06ycgp7D8msxSvtc4HXL9BLdj2elSEfhBJAI0QNgJEBI1BEBsQClVBVGDgwYOLAhJkDM1YOrNg4sLFAsLJgZsHEgoEFFQt0JAFGFjQsKAMJ0LFAexKgZYFyJIDxJIBNJEDNAtSJBLCeBDCOBFAPzwFA94ED+zmhwDO9358r8ANtIsMXi7qVAwAAAABJRU5ErkJggg==';
@ -10,14 +11,34 @@ export const widgetHolder = document.createElement('div');
export const bubbleHolder = document.createElement('div');
export const chatBubble = document.createElement('div');
export const closeBubble = document.createElement('div');
export const notificationBubble = document.createElement('span');
export const getBubbleView = type =>
BUBBLE_DESIGN.includes(type) ? type : BUBBLE_DESIGN[0];
export const isExpandedView = type => getBubbleView(type) === BUBBLE_DESIGN[1];
export const setBubbleText = bubbleText => {
if (isExpandedView(window.$chatwoot.type)) {
const textNode = document.getElementById('woot-widget--expanded__text');
textNode.innerHTML = bubbleText;
}
};
export const createBubbleIcon = ({ className, src, target }) => {
target.className = `${className} woot-elements--${window.$chatwoot.position}`;
let bubbleClassName = `${className} woot-elements--${window.$chatwoot.position}`;
const bubbleIcon = document.createElement('img');
bubbleIcon.src = src;
target.appendChild(bubbleIcon);
if (isExpandedView(window.$chatwoot.type)) {
const textNode = document.createElement('div');
textNode.id = 'woot-widget--expanded__text';
textNode.innerHTML = '';
target.appendChild(textNode);
bubbleClassName += ' woot-widget--expanded';
}
target.className = bubbleClassName;
return target;
};

View file

@ -0,0 +1 @@
export const BUBBLE_DESIGN = ['standard', 'expanded_bubble'];

View file

@ -1,50 +1,60 @@
export const SDK_CSS = `.woot-widget-holder {
z-index: 2147483000 !important;
position: fixed !important;
-moz-box-shadow: 0 5px 40px rgba(0, 0, 0, .16) !important;
-o-box-shadow: 0 5px 40px rgba(0, 0, 0, .16) !important;
-webkit-box-shadow: 0 5px 40px rgba(0, 0, 0, .16) !important;
box-shadow: 0 5px 40px rgba(0, 0, 0, .16) !important;
overflow: hidden !important;
opacity: 1;
transition-property: opacity, bottom;
overflow: hidden !important;
position: fixed !important;
transition-duration: 0.5s, 0.5s;
}
.woot-widget-holder.has-unread-view {
box-shadow: none !important;
-moz-box-shadow: none !important;
-o-box-shadow: none !important;
-webkit-box-shadow: none !important;
-o-border-radius: 0 !important;
-moz-border-radius: 0 !important;
-webkit-border-radius: 0 !important;
border-radius: 0 !important;
bottom: 94px;
transition-property: opacity, bottom;
z-index: 2147483000 !important;
}
.woot-widget-holder iframe {
width: 100% !important;
height: 100% !important;
border: 0;
height: 100% !important;
width: 100% !important;
}
.woot-widget-holder.has-unread-view {
border-radius: 0 !important;
bottom: 94px;
box-shadow: none !important;
}
.woot-widget-bubble {
z-index: 2147483000 !important;
-moz-box-shadow: 0 8px 24px rgba(0, 0, 0, .16) !important;
-o-box-shadow: 0 8px 24px rgba(0, 0, 0, .16) !important;
-webkit-box-shadow: 0 8px 24px rgba(0, 0, 0, .16) !important;
box-shadow: 0 8px 24px rgba(0, 0, 0, .16) !important;
-o-border-radius: 100px !important;
-moz-border-radius: 100px !important;
-webkit-border-radius: 100px !important;
border-radius: 100px !important;
background: #1f93ff;
position: fixed;
cursor: pointer;
border-radius: 100px !important;
bottom: 20px;
width: 64px !important;
box-shadow: 0 8px 24px rgba(0, 0, 0, .16) !important;
cursor: pointer;
height: 64px !important;
position: fixed;
width: 64px !important;
z-index: 2147483000 !important;
}
.woot-widget-bubble.woot-widget--expanded {
bottom: 24px;
display: flex;
height: 48px !important;
width: auto !important;
}
.woot-widget-bubble.woot-widget--expanded div {
align-items: center;
color: #fff;
display: flex;
font-family: system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, Arial, sans-serif;
font-size: 16px;
font-weight: 500;
justify-content: center;
padding-right: 20px;
width: auto !important;
}
.woot-widget-bubble.woot-widget--expanded img {
height: 20px;
margin: 14px 8px 14px 16px;
width: 20px;
}
.woot-widget-bubble.woot-elements--left {
@ -55,87 +65,78 @@ export const SDK_CSS = ` .woot-widget-holder {
right: 20px;
}
@media only screen and (min-width: 667px) {
.woot-widget-holder.woot-elements--left {
left: 20px;
}
.woot-widget-holder.woot-elements--right {
right: 20px;
}
}
.woot-widget-bubble:hover {
background: #1f93ff;
-moz-box-shadow: 0 8px 32px rgba(0, 0, 0, .4) !important;
-o-box-shadow: 0 8px 32px rgba(0, 0, 0, .4) !important;
-webkit-box-shadow: 0 8px 32px rgba(0, 0, 0, .4) !important;
box-shadow: 0 8px 32px rgba(0, 0, 0, .4) !important;
}
.woot-widget-bubble img {
width: 24px;
height: 24px;
margin: 20px;
width: 24px;
}
@media only screen and (min-width: 667px) {
.woot-widget-holder.woot-elements--left {
left: 20px;
}
.woot-widget-holder.woot-elements--right {
right: 20px;
}
}
.woot--close:hover {
opacity: 1;
}
.woot--close:before, .woot--close:after {
position: absolute;
left: 32px;
top: 20px;
.woot--close::before, .woot--close::after {
background-color: #fff;
content: ' ';
height: 24px;
left: 32px;
position: absolute;
top: 20px;
width: 2px;
background-color: white;
}
.woot--close:before {
.woot--close::before {
transform: rotate(45deg);
}
.woot--close:after {
.woot--close::after {
transform: rotate(-45deg);
}
.woot--hide {
bottom: -20000px;
opacity: 0;
visibility: hidden !important;
z-index: -1 !important;
opacity: 0;
bottom: -20000px;
}
@media only screen and (max-width: 667px) {
.woot-widget-holder {
top: 0;
right: 0;
height: 100%;
right: 0;
top: 0;
width: 100%;
}
.woot-widget-bubble.woot--close {
bottom: 60px;
opacity: 0;
visibility: hidden !important;
z-index: -1 !important;
opacity: 0;
bottom: 60px;
}
}
@media only screen and (min-width: 667px) {
.woot-widget-holder {
border-radius: 16px !important;
bottom: 104px;
height: calc(85% - 64px - 20px);
width: 400px !important;
min-height: 250px !important;
max-height: 590px !important;
-o-border-radius: 16px !important;
-moz-border-radius: 16px !important;
-webkit-border-radius: 16px !important;
border-radius: 16px !important;
min-height: 250px !important;
width: 400px !important;
}
}
`;

View file

@ -0,0 +1,17 @@
import { getBubbleView, isExpandedView } from '../bubbleHelpers';
describe('#getBubbleView', () => {
it('returns correct view', () => {
expect(getBubbleView('')).toEqual('standard');
expect(getBubbleView('standard')).toEqual('standard');
expect(getBubbleView('expanded_bubble')).toEqual('expanded_bubble');
});
});
describe('#isExpandedView', () => {
it('returns true if it is expanded view', () => {
expect(isExpandedView('')).toEqual(false);
expect(isExpandedView('standard')).toEqual(false);
expect(isExpandedView('expanded_bubble')).toEqual(true);
});
});

View file

@ -77,12 +77,13 @@ export default {
const message = JSON.parse(e.data.replace(wootPrefix, ''));
if (message.event === 'config-set') {
this.setLocale(message.locale);
this.setBubbleLabel();
this.setPosition(message.position);
this.fetchOldConversations().then(() => {
this.setUnreadView();
});
this.fetchAvailableAgents(websiteToken);
this.setLocale(message.locale);
this.setPosition(message.position);
this.setHideMessageBubble(message.hideMessageBubble);
} else if (message.event === 'widget-visible') {
this.scrollConversationToBottom();
@ -100,6 +101,7 @@ export default {
this.$store.dispatch('contacts/update', message);
} else if (message.event === 'set-locale') {
this.setLocale(message.locale);
this.setBubbleLabel();
} else if (message.event === 'set-unread-view') {
this.showUnreadView = true;
} else if (message.event === 'unset-unread-view') {
@ -118,6 +120,12 @@ export default {
const container = this.$el.querySelector('.conversation-wrap');
container.scrollTop = container.scrollHeight;
},
setBubbleLabel() {
IFrameHelper.sendMessage({
event: 'setBubbleLabel',
label: this.$t('BUBBLE.LABEL'),
});
},
setLocale(locale) {
const { enabledLanguages } = window.chatwootWebChannel;
if (enabledLanguages.some(lang => lang.iso_639_1_code === locale)) {

View file

@ -18,6 +18,9 @@
"VIEW_MESSAGES_BUTTON": "See new messages",
"CLOSE_MESSAGES_BUTTON": "Close"
},
"BUBBLE": {
"LABEL": "Chat with us"
},
"POWERED_BY": "Powered by Chatwoot",
"EMAIL_PLACEHOLDER": "Please enter your email",
"CHAT_PLACEHOLDER": "Type your message"

View file

@ -14,6 +14,9 @@
"OTHERS_ARE_AVAILABLE": "d'autres sont disponibles",
"AND": "et"
},
"BUBBLE": {
"LABEL": "Discute avec nous"
},
"POWERED_BY": "Propulsé par Chatwoot",
"EMAIL_PLACEHOLDER": "Veuillez saisir votre adresse de courriel",
"CHAT_PLACEHOLDER": "Tapez votre message"

View file

@ -14,6 +14,9 @@
"OTHERS_ARE_AVAILABLE": "others are available",
"AND": "and"
},
"BUBBLE": {
"LABEL": "ഞങ്ങളുമായി ചാറ്റുചെയ്യുക"
},
"POWERED_BY": "Powered by Chatwoot",
"EMAIL_PLACEHOLDER": "ദയവായി നിങ്ങളുടെ ഇമെയിൽ നൽകുക",
"CHAT_PLACEHOLDER": "Type your message"

View file

@ -14,6 +14,9 @@
"OTHERS_ARE_AVAILABLE": "others are available",
"AND": "and"
},
"BUBBLE": {
"LABEL": "Chat met ons"
},
"POWERED_BY": "Mogelijk gemaakt door Chatwoot",
"EMAIL_PLACEHOLDER": "Voer uw e-mailadres in",
"CHAT_PLACEHOLDER": "Typ uw bericht"

View file

@ -6,6 +6,7 @@ window.chatwootSettings = {
hideMessageBubble: false,
position: 'left',
locale: 'en',
type: 'expanded_bubble',
};
(function(d,t) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View file

@ -23,9 +23,20 @@ window.chatwootSettings = {
hideMessageBubble: false,
position: 'left', // This can be left or right
locale: 'en', // Language to be set
type: 'standard', // [standard, expanded_bubble]
};
```
Chatwoot support 2 designs for for the widget
1. Standard (default)
![Standard-bubble](./images/sdk/standard-bubble.gif)
2. Expanded bubble
![Expanded-bubble](./images/sdk/expanded-bubble.gif)
### To trigger widget without displaying bubble
```js