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:
parent
a04ca24def
commit
0adbc346df
16 changed files with 164 additions and 84 deletions
|
@ -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();
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
1
app/javascript/sdk/constants.js
Normal file
1
app/javascript/sdk/constants.js
Normal file
|
@ -0,0 +1 @@
|
|||
export const BUBBLE_DESIGN = ['standard', 'expanded_bubble'];
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
`;
|
17
app/javascript/sdk/specs/bubbleHelpers.spec.js
Normal file
17
app/javascript/sdk/specs/bubbleHelpers.spec.js
Normal 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);
|
||||
});
|
||||
});
|
|
@ -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)) {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -6,6 +6,7 @@ window.chatwootSettings = {
|
|||
hideMessageBubble: false,
|
||||
position: 'left',
|
||||
locale: 'en',
|
||||
type: 'expanded_bubble',
|
||||
};
|
||||
|
||||
(function(d,t) {
|
||||
|
|
BIN
docs/channels/images/sdk/expanded-bubble.gif
Normal file
BIN
docs/channels/images/sdk/expanded-bubble.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
BIN
docs/channels/images/sdk/standard-bubble.gif
Normal file
BIN
docs/channels/images/sdk/standard-bubble.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
|
@ -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)
|
||||
|
||||

|
||||
|
||||
2. Expanded bubble
|
||||
|
||||

|
||||
|
||||
### To trigger widget without displaying bubble
|
||||
|
||||
```js
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue