Feature: Update design for web widget (#408)

This commit is contained in:
Nithin David Thomas 2020-01-13 12:10:40 +05:30 committed by Pranav Raj S
parent 655c585358
commit 7cf19e0b52
11 changed files with 184 additions and 77 deletions

View file

@ -4,8 +4,6 @@ import { SDK_CSS } from '../widget/assets/scss/sdk';
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
const bubbleImg = const bubbleImg =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAUVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////8IN+deAAAAGnRSTlMAAwgJEBk0TVheY2R5eo+ut8jb5OXs8fX2+cjRDTIAAADsSURBVHgBldZbkoMgFIThRgQv8SKKgGf/C51UnJqaRI30/9zfe+NQUQ3TvG7bOk9DVeCmshmj/CuOTYnrdBfkUOg0zlOtl9OWVuEk4+QyZ3DIevmSt/ioTvK1VH/s5bY3YdM9SBZ/mUUyWgx+U06ycgp7D8msxSvtc4HXL9BLdj2elSEfhBJAI0QNgJEBI1BEBsQClVBVGDgwYOLAhJkDM1YOrNg4sLFAsLJgZsHEgoEFFQt0JAFGFjQsKAMJ0LFAexKgZYFyJIDxJIBNJEDNAtSJBLCeBDCOBFAPzwFA94ED+zmhwDO9358r8ANtIsMXi7qVAwAAAABJRU5ErkJggg=='; 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAUVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////8IN+deAAAAGnRSTlMAAwgJEBk0TVheY2R5eo+ut8jb5OXs8fX2+cjRDTIAAADsSURBVHgBldZbkoMgFIThRgQv8SKKgGf/C51UnJqaRI30/9zfe+NQUQ3TvG7bOk9DVeCmshmj/CuOTYnrdBfkUOg0zlOtl9OWVuEk4+QyZ3DIevmSt/ioTvK1VH/s5bY3YdM9SBZ/mUUyWgx+U06ycgp7D8msxSvtc4HXL9BLdj2elSEfhBJAI0QNgJEBI1BEBsQClVBVGDgwYOLAhJkDM1YOrNg4sLFAsLJgZsHEgoEFFQt0JAFGFjQsKAMJ0LFAexKgZYFyJIDxJIBNJEDNAtSJBLCeBDCOBFAPzwFA94ED+zmhwDO9358r8ANtIsMXi7qVAwAAAABJRU5ErkJggg==';
const closeImg =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAP1BMVEUAAAD///////////////////////////////////////////////////////////////////////////////9Du/pqAAAAFHRSTlMACBstLi8wMVB+mcbT2err7O3w8n+sjtQAAAEuSURBVHgBtNLdcoMgGITh1SCGH9DId//X2mnTg7hYxj0oh8w8r+MqgDnmlsIE6UwhtRxnAHge9n2KV7wvP+h4AvPbm73W+359/aJjRjQTCuTNIrJJBfKW0UwqkLeGZJ8Ff2O/T28JwZQCewuYilJgX6buavdDv188br1RIE+jc2H5yy+9VwrXXij0nsflwth7YFRw7N3Y88BcYL+z7wubO/lt6AcFwQMLF9irP8r2eF8/ei8VLrxUkDzguMDejX03WK3dsGJB9lxgrxd0T8PTRxUL5OUCealQz76KXg/or/CvI36VXgcEAAAgCMP6t16IZVDg3zPuI+0rb5g2zlsoW2lbqlvrOyw7bTuuO+8LGIs4C1mLeQuai7oL2437LRytPC1drX0tnq2+Ld+r/wDPIIIJkfdlbQAAAABJRU5ErkJggg==';
const body = document.getElementsByTagName('body')[0]; const body = document.getElementsByTagName('body')[0];
const holder = document.createElement('div'); const holder = document.createElement('div');
@ -189,11 +187,8 @@ const IFrameHelper = {
target: chatBubble, target: chatBubble,
}); });
const closeIcon = createBubbleIcon({ const closeIcon = closeBubble;
className: 'woot-widget-bubble woot--close woot--hide', closeIcon.className = 'woot-widget-bubble woot--close woot--hide';
src: closeImg,
target: closeBubble,
});
chatIcon.style.background = widgetColor; chatIcon.style.background = widgetColor;
closeIcon.style.background = widgetColor; closeIcon.style.background = widgetColor;

View file

@ -1,44 +1,47 @@
export const SDK_CSS = ` export const SDK_CSS = ` .woot-widget-holder {
.woot-widget-holder { z-index: 2147483000 !important;
z-index: 2147483000!important; position: fixed !important;
position: fixed!important; -moz-box-shadow: 0 5px 40px rgba(0, 0, 0, .16) !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;
-o-box-shadow: 0 5px 40px rgba(0,0,0,.16)!important; -webkit-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;
box-shadow: 0 5px 40px rgba(0,0,0,.16)!important; overflow: hidden !important;
overflow: hidden!important;
opacity: 1; opacity: 1;
transition-property: opacity, bottom; transition-property: opacity, bottom;
transition-duration: 0.5s, 0.5s; transition-duration: 0.5s, 0.5s;
} }
.woot-widget-holder iframe { width: 100% !important; height: 100% !important; border: 0; } .woot-widget-holder iframe {
width: 100% !important;
height: 100% !important;
border: 0;
}
.woot-widget-bubble { .woot-widget-bubble {
z-index: 2147483000!important; z-index: 2147483000 !important;
-moz-box-shadow: 0 8px 24px rgba(0,0,0,.16)!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; -o-box-shadow: 0 8px 24px rgba(0, 0, 0, .16) !important;
-webkit-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; box-shadow: 0 8px 24px rgba(0, 0, 0, .16) !important;
-o-border-radius: 100px!important; -o-border-radius: 100px !important;
-moz-border-radius: 100px!important; -moz-border-radius: 100px !important;
-webkit-border-radius: 100px!important; -webkit-border-radius: 100px !important;
border-radius: 100px!important; border-radius: 100px !important;
background: #1f93ff; background: #1f93ff;
position: fixed; position: fixed;
cursor: pointer; cursor: pointer;
right: 20px; right: 20px;
bottom: 20px; bottom: 20px;
width: 64px!important; width: 64px !important;
height: 64px!important; height: 64px !important;
} }
.woot-widget-bubble:hover { .woot-widget-bubble:hover {
background: #1f93ff; background: #1f93ff;
-moz-box-shadow: 0 8px 32px rgba(0,0,0,.4)!important; -moz-box-shadow: 0 8px 32px rgba(0, 0, 0, .4) !important;
-o-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; -webkit-box-shadow: 0 8px 32px rgba(0, 0, 0, .4) !important;
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 { .woot-widget-bubble img {
@ -47,15 +50,29 @@ export const SDK_CSS = `
margin: 20px; margin: 20px;
} }
.woot-widget-bubble.woot--close img { .woot--close:hover {
width: 16px; opacity: 1;
height: 16px;
margin: 24px;
} }
.woot--close:before, .woot--close:after {
position: absolute;
left: 30px;
top: 15px;
content: ' ';
height: 33px;
width: 2px;
background-color: white;
}
.woot--close:before {
transform: rotate(45deg);
}
.woot--close:after {
transform: rotate(-45deg);
}
.woot--hide { .woot--hide {
visibility: hidden !important; visibility: hidden !important;
z-index: -1!important; z-index: -1 !important;
opacity: 0; opacity: 0;
bottom: 60px; bottom: 60px;
} }
@ -69,12 +86,17 @@ export const SDK_CSS = `
} }
.woot-widget-bubble.woot--close { .woot-widget-bubble.woot--close {
top: 0; top: 8px;
right: 0; right: 8px;
box-shadow: none !important; box-shadow: none !important;
-moz-box-shadow: none !important; -moz-box-shadow: none !important;
-o-box-shadow: none !important; -o-box-shadow: none !important;
-webkit-box-shadow: none !important; -webkit-box-shadow: none !important;
background: transparent !important;
}
.woot--close:before, .woot--close:after {
background-color: black;
} }
} }
@ -83,13 +105,13 @@ export const SDK_CSS = `
bottom: 104px; bottom: 104px;
right: 20px; right: 20px;
height: calc(85% - 64px - 20px); height: calc(85% - 64px - 20px);
width: 370px!important; width: 400px !important;
min-height: 250px!important; min-height: 250px !important;
max-height: 590px!important; max-height: 590px !important;
-o-border-radius: 8px!important; -o-border-radius: 8px !important;
-moz-border-radius: 8px!important; -moz-border-radius: 8px !important;
-webkit-border-radius: 8px!important; -webkit-border-radius: 8px !important;
border-radius: 8px!important; border-radius: 8px !important;
} }
} }

View file

@ -16,22 +16,26 @@
.branding { .branding {
align-items: center; align-items: center;
color: $color-gray; color: $color-light-gray;
opacity: 0.9;
display: flex; display: flex;
filter: grayscale(1); filter: grayscale(1);
font-size: $font-size-default; font-size: $font-size-small;
justify-content: center; justify-content: center;
padding: $space-one;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
padding: $space-slab 0;
cursor: pointer;
&:hover { &:hover {
filter: grayscale(0); filter: grayscale(0);
opacity: 1;
color: $color-gray;
} }
img { img {
margin-right: $space-small; margin-right: $space-smaller;
max-width: $space-two; max-width: $space-slab;
} }
} }
</style> </style>

View file

@ -12,8 +12,14 @@ export default {
ChatInputWrap, ChatInputWrap,
}, },
props: { props: {
msg: String, msg: {
onSendMessage: Function, type: String,
default: '',
},
onSendMessage: {
type: Function,
default: () => {},
},
}, },
}; };
</script> </script>
@ -24,11 +30,12 @@ export default {
.footer { .footer {
background: $color-white; background: $color-white;
box-shadow: 0 -$space-micro 3px rgba(50, 50, 93, 0.04),
0 -1px 2px rgba(0, 0, 0, 0.03);
box-sizing: border-box; box-sizing: border-box;
padding: $space-small; padding: $space-small $space-slab;
width: 100%; width: 100%;
border-radius: 7px;
box-shadow: 0 20px 25px -10px rgba(0, 0, 0, 0.1),
0 10px 10px -10px rgba(0, 0, 0, 0.04) !important;
} }
.branding { .branding {

View file

@ -1,6 +1,10 @@
<template> <template>
<header class="header-expanded" :style="{ background: widgetColor }"> <header class="header-expanded">
<div> <div>
<!-- <img
class="logo"
src="http://www.hennigcompany.com/wp-content/uploads/2014/06/starbucks-logo.png"
/> -->
<h2 class="title"> <h2 class="title">
{{ introHeading }} {{ introHeading }}
</h2> </h2>
@ -39,21 +43,35 @@ export default {
@import '~widget/assets/scss/variables.scss'; @import '~widget/assets/scss/variables.scss';
.header-expanded { .header-expanded {
background: $color-woot; background: $color-white;
padding: $space-large; padding: $space-larger $space-medium $space-large;
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
color: $color-white; border-radius: 1.6rem;
box-shadow: 0 10px 15px -16px rgba(0, 0, 0, 0.1),
0 4px 6px -8px rgba(0, 0, 0, 0.05) !important;
@media only screen and (min-device-width: 320px) and (max-device-width: 480px) {
border-radius: 0;
}
.logo {
width: 64px;
height: 64px;
}
.title { .title {
color: $color-heading;
font-size: $font-size-mega; font-size: $font-size-mega;
font-weight: $font-weight-medium; font-weight: $font-weight-normal;
margin-bottom: $space-two; margin-bottom: $space-slab;
margin-top: $space-large;
} }
.body { .body {
font-size: $font-size-medium; color: $color-body;
line-height: 1.5; font-size: 1.8rem;
line-height: 1.6;
} }
} }
</style> </style>

View file

@ -1,14 +1,21 @@
<template> <template>
<textarea <resizable-textarea>
class="form-input user-message-input" <textarea
:placeholder="placeholder" class="form-input user-message-input"
:value="value" :placeholder="placeholder"
@input="$emit('input', $event.target.value)" :value="value"
/> @input="$emit('input', $event.target.value)"
/>
</resizable-textarea>
</template> </template>
<script> <script>
import ResizableTextarea from 'widget/components/ResizableTextarea.vue';
export default { export default {
components: {
ResizableTextarea,
},
props: { props: {
placeholder: String, placeholder: String,
value: String, value: String,
@ -24,5 +31,6 @@ export default {
border: 0; border: 0;
height: $space-large; height: $space-large;
resize: none; resize: none;
padding-top: $space-small;
} }
</style> </style>

View file

@ -4,11 +4,13 @@
<ChatSendButton <ChatSendButton
:on-click="handleButtonClick" :on-click="handleButtonClick"
:disabled="!userInput.length" :disabled="!userInput.length"
:color="widgetColor"
/> />
</div> </div>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex';
import ChatSendButton from 'widget/components/ChatSendButton.vue'; import ChatSendButton from 'widget/components/ChatSendButton.vue';
import ChatInputArea from 'widget/components/ChatInputArea.vue'; import ChatInputArea from 'widget/components/ChatInputArea.vue';
@ -42,6 +44,11 @@ export default {
document.addEventListener('keypress', this.handleEnterKeyPress); document.addEventListener('keypress', this.handleEnterKeyPress);
}, },
computed: {
...mapGetters({
widgetColor: 'appConfig/getWidgetColor',
}),
},
methods: { methods: {
handleButtonClick() { handleButtonClick() {
if (this.userInput && this.userInput.trim()) { if (this.userInput && this.userInput.trim()) {

View file

@ -5,9 +5,11 @@
class="send-button" class="send-button"
@click="onClick" @click="onClick"
> >
<span v-if="!loading" class="icon-holder"> <span
<i class="ion-android-send" /> v-if="!loading"
</span> :style="`background-color: ${color}`"
class="icon-holder"
></span>
<spinner v-else size="small" /> <spinner v-else size="small" />
</button> </button>
</template> </template>
@ -32,6 +34,10 @@ export default {
type: Function, type: Function,
default: () => {}, default: () => {},
}, },
color: {
type: String,
default: '#6e6f73',
},
}, },
}; };
</script> </script>
@ -45,6 +51,7 @@ export default {
border: 0; border: 0;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
padding-right: $space-smaller;
.icon-holder { .icon-holder {
display: flex; display: flex;
@ -53,6 +60,10 @@ export default {
fill: $color-white; fill: $color-white;
font-size: $font-size-big; font-size: $font-size-big;
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
width: $space-two;
height: $space-two;
-webkit-mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='20' height='20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.34 7.32l-14-7a3 3 0 00-4.08 3.9l2.4 5.37c.11.262.11.558 0 .82l-2.4 5.37A3 3 0 003 20a3.14 3.14 0 001.35-.32l14-7a3 3 0 000-5.36h-.01zm-.89 3.57l-14 7a1 1 0 01-1.35-1.3l2.39-5.37a2 2 0 00.08-.22h6.89a1 1 0 000-2H4.57a2 2 0 00-.08-.22L2.1 3.41a1 1 0 011.35-1.3l14 7a1 1 0 010 1.78z' fill='%23999A9B' fill-rule='nonzero'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='20' height='20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.34 7.32l-14-7a3 3 0 00-4.08 3.9l2.4 5.37c.11.262.11.558 0 .82l-2.4 5.37A3 3 0 003 20a3.14 3.14 0 001.35-.32l14-7a3 3 0 000-5.36h-.01zm-.89 3.57l-14 7a1 1 0 01-1.35-1.3l2.39-5.37a2 2 0 00.08-.22h6.89a1 1 0 000-2H4.57a2 2 0 00-.08-.22L2.1 3.41a1 1 0 011.35-1.3l14 7a1 1 0 010 1.78z' fill='%23999A9B' fill-rule='nonzero'/%3E%3C/svg%3E");
} }
} }
</style> </style>

View file

@ -13,12 +13,10 @@
/> />
</div> </div>
</div> </div>
<branding></branding>
</div> </div>
</template> </template>
<script> <script>
import Branding from 'widget/components/Branding.vue';
import ChatMessage from 'widget/components/ChatMessage.vue'; import ChatMessage from 'widget/components/ChatMessage.vue';
import DateSeparator from 'shared/components/DateSeparator.vue'; import DateSeparator from 'shared/components/DateSeparator.vue';
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
@ -27,7 +25,6 @@ import { mapActions, mapGetters } from 'vuex';
export default { export default {
name: 'ConversationWrap', name: 'ConversationWrap',
components: { components: {
Branding,
ChatMessage, ChatMessage,
DateSeparator, DateSeparator,
Spinner, Spinner,

View file

@ -0,0 +1,26 @@
<script>
export default {
mounted() {
this.$nextTick(() => {
this.$el.setAttribute(
'style',
`height: ${this.$el.scrollHeight}px;overflow-y:hidden;`
);
});
this.$el.addEventListener('input', this.resizeTextarea);
},
beforeDestroy() {
this.$el.removeEventListener('input', this.resizeTextarea);
},
methods: {
resizeTextarea(event) {
event.target.style.height = '3.2rem';
event.target.style.height = `${event.target.scrollHeight}px`;
},
},
render() {
return this.$slots.default[0];
},
};
</script>

View file

@ -6,7 +6,10 @@
</div> </div>
<ConversationWrap :grouped-messages="groupedMessages" /> <ConversationWrap :grouped-messages="groupedMessages" />
<div class="footer-wrap"> <div class="footer-wrap">
<ChatFooter :on-send-message="handleSendMessage" /> <div class="input-wrap">
<ChatFooter :on-send-message="handleSendMessage" />
</div>
<branding></branding>
</div> </div>
</div> </div>
</template> </template>
@ -14,6 +17,7 @@
<script> <script>
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import Branding from 'widget/components/Branding.vue';
import ChatFooter from 'widget/components/ChatFooter.vue'; import ChatFooter from 'widget/components/ChatFooter.vue';
import ChatHeaderExpanded from 'widget/components/ChatHeaderExpanded.vue'; import ChatHeaderExpanded from 'widget/components/ChatHeaderExpanded.vue';
import ChatHeader from 'widget/components/ChatHeader.vue'; import ChatHeader from 'widget/components/ChatHeader.vue';
@ -26,6 +30,7 @@ export default {
ChatHeaderExpanded, ChatHeaderExpanded,
ConversationWrap, ConversationWrap,
ChatHeader, ChatHeader,
Branding,
}, },
methods: { methods: {
...mapActions('conversation', ['sendMessage']), ...mapActions('conversation', ['sendMessage']),
@ -67,6 +72,13 @@ export default {
.footer-wrap { .footer-wrap {
flex-shrink: 0; flex-shrink: 0;
width: 100%;
display: flex;
flex-direction: column;
}
.input-wrap {
padding: 0 $space-medium;
} }
} }
</style> </style>