Feature: Update design for web widget (#408)
This commit is contained in:
parent
655c585358
commit
7cf19e0b52
11 changed files with 184 additions and 77 deletions
|
@ -4,8 +4,6 @@ import { SDK_CSS } from '../widget/assets/scss/sdk';
|
|||
/* eslint-disable no-param-reassign */
|
||||
const bubbleImg =
|
||||
'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 holder = document.createElement('div');
|
||||
|
@ -189,11 +187,8 @@ const IFrameHelper = {
|
|||
target: chatBubble,
|
||||
});
|
||||
|
||||
const closeIcon = createBubbleIcon({
|
||||
className: 'woot-widget-bubble woot--close woot--hide',
|
||||
src: closeImg,
|
||||
target: closeBubble,
|
||||
});
|
||||
const closeIcon = closeBubble;
|
||||
closeIcon.className = 'woot-widget-bubble woot--close woot--hide';
|
||||
|
||||
chatIcon.style.background = widgetColor;
|
||||
closeIcon.style.background = widgetColor;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export const SDK_CSS = `
|
||||
.woot-widget-holder {
|
||||
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;
|
||||
|
@ -12,7 +11,11 @@ export const SDK_CSS = `
|
|||
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 {
|
||||
z-index: 2147483000 !important;
|
||||
|
@ -47,11 +50,25 @@ export const SDK_CSS = `
|
|||
margin: 20px;
|
||||
}
|
||||
|
||||
.woot-widget-bubble.woot--close img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 24px;
|
||||
.woot--close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.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 {
|
||||
visibility: hidden !important;
|
||||
|
@ -69,12 +86,17 @@ export const SDK_CSS = `
|
|||
}
|
||||
|
||||
.woot-widget-bubble.woot--close {
|
||||
top: 0;
|
||||
right: 0;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
box-shadow: none !important;
|
||||
-moz-box-shadow: none !important;
|
||||
-o-box-shadow: none !important;
|
||||
-webkit-box-shadow: none !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.woot--close:before, .woot--close:after {
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +105,7 @@ export const SDK_CSS = `
|
|||
bottom: 104px;
|
||||
right: 20px;
|
||||
height: calc(85% - 64px - 20px);
|
||||
width: 370px!important;
|
||||
width: 400px !important;
|
||||
min-height: 250px !important;
|
||||
max-height: 590px !important;
|
||||
-o-border-radius: 8px !important;
|
||||
|
|
|
@ -16,22 +16,26 @@
|
|||
|
||||
.branding {
|
||||
align-items: center;
|
||||
color: $color-gray;
|
||||
color: $color-light-gray;
|
||||
opacity: 0.9;
|
||||
display: flex;
|
||||
filter: grayscale(1);
|
||||
font-size: $font-size-default;
|
||||
font-size: $font-size-small;
|
||||
justify-content: center;
|
||||
padding: $space-one;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
padding: $space-slab 0;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
filter: grayscale(0);
|
||||
opacity: 1;
|
||||
color: $color-gray;
|
||||
}
|
||||
|
||||
img {
|
||||
margin-right: $space-small;
|
||||
max-width: $space-two;
|
||||
margin-right: $space-smaller;
|
||||
max-width: $space-slab;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -12,8 +12,14 @@ export default {
|
|||
ChatInputWrap,
|
||||
},
|
||||
props: {
|
||||
msg: String,
|
||||
onSendMessage: Function,
|
||||
msg: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
onSendMessage: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -24,11 +30,12 @@ export default {
|
|||
|
||||
.footer {
|
||||
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;
|
||||
padding: $space-small;
|
||||
padding: $space-small $space-slab;
|
||||
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 {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<template>
|
||||
<header class="header-expanded" :style="{ background: widgetColor }">
|
||||
<header class="header-expanded">
|
||||
<div>
|
||||
<!-- <img
|
||||
class="logo"
|
||||
src="http://www.hennigcompany.com/wp-content/uploads/2014/06/starbucks-logo.png"
|
||||
/> -->
|
||||
<h2 class="title">
|
||||
{{ introHeading }}
|
||||
</h2>
|
||||
|
@ -39,21 +43,35 @@ export default {
|
|||
@import '~widget/assets/scss/variables.scss';
|
||||
|
||||
.header-expanded {
|
||||
background: $color-woot;
|
||||
padding: $space-large;
|
||||
background: $color-white;
|
||||
padding: $space-larger $space-medium $space-large;
|
||||
width: 100%;
|
||||
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 {
|
||||
color: $color-heading;
|
||||
font-size: $font-size-mega;
|
||||
font-weight: $font-weight-medium;
|
||||
margin-bottom: $space-two;
|
||||
font-weight: $font-weight-normal;
|
||||
margin-bottom: $space-slab;
|
||||
margin-top: $space-large;
|
||||
}
|
||||
|
||||
.body {
|
||||
font-size: $font-size-medium;
|
||||
line-height: 1.5;
|
||||
color: $color-body;
|
||||
font-size: 1.8rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
<template>
|
||||
<resizable-textarea>
|
||||
<textarea
|
||||
class="form-input user-message-input"
|
||||
:placeholder="placeholder"
|
||||
:value="value"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
/>
|
||||
</resizable-textarea>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ResizableTextarea from 'widget/components/ResizableTextarea.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ResizableTextarea,
|
||||
},
|
||||
props: {
|
||||
placeholder: String,
|
||||
value: String,
|
||||
|
@ -24,5 +31,6 @@ export default {
|
|||
border: 0;
|
||||
height: $space-large;
|
||||
resize: none;
|
||||
padding-top: $space-small;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
<ChatSendButton
|
||||
:on-click="handleButtonClick"
|
||||
:disabled="!userInput.length"
|
||||
:color="widgetColor"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import ChatSendButton from 'widget/components/ChatSendButton.vue';
|
||||
import ChatInputArea from 'widget/components/ChatInputArea.vue';
|
||||
|
||||
|
@ -42,6 +44,11 @@ export default {
|
|||
document.addEventListener('keypress', this.handleEnterKeyPress);
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters({
|
||||
widgetColor: 'appConfig/getWidgetColor',
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
handleButtonClick() {
|
||||
if (this.userInput && this.userInput.trim()) {
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
class="send-button"
|
||||
@click="onClick"
|
||||
>
|
||||
<span v-if="!loading" class="icon-holder">
|
||||
<i class="ion-android-send" />
|
||||
</span>
|
||||
<span
|
||||
v-if="!loading"
|
||||
:style="`background-color: ${color}`"
|
||||
class="icon-holder"
|
||||
></span>
|
||||
<spinner v-else size="small" />
|
||||
</button>
|
||||
</template>
|
||||
|
@ -32,6 +34,10 @@ export default {
|
|||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#6e6f73',
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -45,6 +51,7 @@ export default {
|
|||
border: 0;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
padding-right: $space-smaller;
|
||||
|
||||
.icon-holder {
|
||||
display: flex;
|
||||
|
@ -53,6 +60,10 @@ export default {
|
|||
fill: $color-white;
|
||||
font-size: $font-size-big;
|
||||
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>
|
||||
|
|
|
@ -13,12 +13,10 @@
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<branding></branding>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Branding from 'widget/components/Branding.vue';
|
||||
import ChatMessage from 'widget/components/ChatMessage.vue';
|
||||
import DateSeparator from 'shared/components/DateSeparator.vue';
|
||||
import Spinner from 'shared/components/Spinner.vue';
|
||||
|
@ -27,7 +25,6 @@ import { mapActions, mapGetters } from 'vuex';
|
|||
export default {
|
||||
name: 'ConversationWrap',
|
||||
components: {
|
||||
Branding,
|
||||
ChatMessage,
|
||||
DateSeparator,
|
||||
Spinner,
|
||||
|
|
26
app/javascript/widget/components/ResizableTextarea.vue
Normal file
26
app/javascript/widget/components/ResizableTextarea.vue
Normal 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>
|
|
@ -6,14 +6,18 @@
|
|||
</div>
|
||||
<ConversationWrap :grouped-messages="groupedMessages" />
|
||||
<div class="footer-wrap">
|
||||
<div class="input-wrap">
|
||||
<ChatFooter :on-send-message="handleSendMessage" />
|
||||
</div>
|
||||
<branding></branding>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
|
||||
import Branding from 'widget/components/Branding.vue';
|
||||
import ChatFooter from 'widget/components/ChatFooter.vue';
|
||||
import ChatHeaderExpanded from 'widget/components/ChatHeaderExpanded.vue';
|
||||
import ChatHeader from 'widget/components/ChatHeader.vue';
|
||||
|
@ -26,6 +30,7 @@ export default {
|
|||
ChatHeaderExpanded,
|
||||
ConversationWrap,
|
||||
ChatHeader,
|
||||
Branding,
|
||||
},
|
||||
methods: {
|
||||
...mapActions('conversation', ['sendMessage']),
|
||||
|
@ -67,6 +72,13 @@ export default {
|
|||
|
||||
.footer-wrap {
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.input-wrap {
|
||||
padding: 0 $space-medium;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in a new issue