Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Juchiha/888a04edb688324ee717e1a00f292244 to your computer and use it in GitHub Desktop.
Save Juchiha/888a04edb688324ee717e1a00f292244 to your computer and use it in GitHub Desktop.
floating website chat button (intercom inspired)
<div class="floating-chat">
<i class="fa fa-comments" aria-hidden="true"></i>
<div class="chat">
<div class="header">
<span class="title">
what's on your mind?
</span>
<button>
<i class="fa fa-times" aria-hidden="true"></i>
</button>
</div>
<ul class="messages">
<li class="other">asdasdasasdasdasasdasdasasdasdasasdasdasasdasdasasdasdas</li>
<li class="other">Are we dogs??? 🐶</li>
<li class="self">no... we're human</li>
<li class="other">are you sure???</li>
<li class="self">yes.... -___-</li>
<li class="other">if we're not dogs.... we might be monkeys 🐵</li>
<li class="self">i hate you</li>
<li class="other">don't be so negative! here's a banana 🍌</li>
<li class="self">......... -___-</li>
</ul>
<div class="footer">
<div class="text-box" contenteditable="true" disabled="true"></div>
<button id="sendMessage">send</button>
</div>
</div>
</div>
var element = $('.floating-chat');
var myStorage = localStorage;
if (!myStorage.getItem('chatID')) {
myStorage.setItem('chatID', createUUID());
}
setTimeout(function() {
element.addClass('enter');
}, 1000);
element.click(openElement);
function openElement() {
var messages = element.find('.messages');
var textInput = element.find('.text-box');
element.find('>i').hide();
element.addClass('expand');
element.find('.chat').addClass('enter');
var strLength = textInput.val().length * 2;
textInput.keydown(onMetaAndEnter).prop("disabled", false).focus();
element.off('click', openElement);
element.find('.header button').click(closeElement);
element.find('#sendMessage').click(sendNewMessage);
messages.scrollTop(messages.prop("scrollHeight"));
}
function closeElement() {
element.find('.chat').removeClass('enter').hide();
element.find('>i').show();
element.removeClass('expand');
element.find('.header button').off('click', closeElement);
element.find('#sendMessage').off('click', sendNewMessage);
element.find('.text-box').off('keydown', onMetaAndEnter).prop("disabled", true).blur();
setTimeout(function() {
element.find('.chat').removeClass('enter').show()
element.click(openElement);
}, 500);
}
function createUUID() {
// http://www.ietf.org/rfc/rfc4122.txt
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
}
function sendNewMessage() {
var userInput = $('.text-box');
var newMessage = userInput.html().replace(/\<div\>|\<br.*?\>/ig, '\n').replace(/\<\/div\>/g, '').trim().replace(/\n/g, '<br>');
if (!newMessage) return;
var messagesContainer = $('.messages');
messagesContainer.append([
'<li class="self">',
newMessage,
'</li>'
].join(''));
// clean out old message
userInput.html('');
// focus on input
userInput.focus();
messagesContainer.finish().animate({
scrollTop: messagesContainer.prop("scrollHeight")
}, 250);
}
function onMetaAndEnter(event) {
if ((event.metaKey || event.ctrlKey) && event.keyCode == 13) {
sendNewMessage();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
// Imports
// --------------------------------------
@import 'https://fonts.googleapis.com/css?family=Noto+Sans';
// Variables
// --------------------------------------
$scrollbar-width: 5px;
$chat-thread-bgd-color: rgba(25, 147, 147, 0.2);
$chat-thread-msg-arrow-size: 10px;
$chat-thread-avatar-size: 25px;
$chat-thread-offset: #{$chat-thread-avatar-size + 20px};
$default-shadow-color: rgb(0, 0, 0);
// Mixins
// --------------------------------------
@mixin fancy-background() {
background: -moz-linear-gradient(-45deg, #183850 0, #183850 25%, #192C46 50%, #22254C 75%, #22254C 100%);
background: -webkit-linear-gradient(-45deg, #183850 0, #183850 25%, #192C46 50%, #22254C 75%, #22254C 100%);
background-repeat: no-repeat;
background-attachment: fixed;
}
@mixin fancy-scrollbar() {
&::-webkit-scrollbar {
width: $scrollbar-width;
}
&::-webkit-scrollbar-track {
border-radius: $scrollbar-width;
background-color: rgba(25, 147, 147, 0.1);
}
&::-webkit-scrollbar-thumb {
border-radius: $scrollbar-width;
background-color: $chat-thread-bgd-color;
}
}
@mixin scrolling-shadows($background-color: transparent, $shadow-intensity: 0.5, $shadow-color: $default-shadow-color, $cover-size: 40px, $shadow-size: 14px) {
// Shadow covers
background: linear-gradient($background-color 30%, rgba($background-color, 0)), linear-gradient(rgba($background-color, 0), $background-color 70%) 0 100%, radial-gradient(50% 0, farthest-side, rgba($shadow-color, $shadow-intensity), rgba($shadow-color, 0)), radial-gradient(50% 100%, farthest-side, rgba($shadow-color, $shadow-intensity), rgba($shadow-color, 0)) 0 100%;
background: linear-gradient($background-color 30%, rgba($background-color, 0)), linear-gradient(rgba($background-color, 0), $background-color 70%) 0 100%, radial-gradient(farthest-side at 50% 0, rgba($shadow-color, $shadow-intensity), rgba($shadow-color, 0));
// also add button shadow:
//radial-gradient(farthest-side at 50% 100%, rgba($shadow-color,$shadow-intensity), rgba($shadow-color,0)) 0 100%;
background-repeat: no-repeat;
background-color: $background-color;
background-size: 100% $cover-size, 100% $cover-size, 100% $shadow-size, 100% $shadow-size;
// Opera doesn't support this in the shorthand
background-attachment: local, local, scroll, scroll;
}
* {
box-sizing: border-box;
}
body {
background: skyblue;
font: 12px/16px 'Noto Sans', sans-serif;
}
.floating-chat {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: white;
position: fixed;
bottom: 10px;
right: 10px;
width: 40px;
height: 40px;
transform: translateY(70px);
transition: all 250ms ease-out;
border-radius: 50%;
opacity: 0;
@include fancy-background;
&.enter:hover {
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
opacity: 1;
}
&.enter {
transform: translateY(0);
opacity: 0.6;
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.12), 0px 1px 2px rgba(0, 0, 0, 0.14);
}
&.expand {
width: 250px;
max-height: 400px;
height: 400px;
border-radius: 5px;
cursor: auto;
opacity: 1;
}
:focus {
outline: 0;
box-shadow: 0 0 3pt 2pt rgba(#0EC879, 0.3);
}
button {
background: transparent;
border: 0;
color: white;
text-transform: uppercase;
border-radius: 3px;
cursor: pointer;
}
.chat {
display: flex;
flex-direction: column;
position: absolute;
opacity: 0;
width: 1px;
height: 1px;
border-radius: 50%;
transition: all 250ms ease-out;
margin: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
&.enter {
opacity: 1;
border-radius: 0;
margin: 10px;
width: auto;
height: auto;
}
.header {
flex-shrink: 0;
padding-bottom: 10px;
display: flex;
background: transparent;
.title {
flex-grow: 1;
flex-shrink: 1;
padding: 0 5px;
}
button {
flex-shrink: 0;
}
}
.messages {
padding: 10px;
margin: 0;
list-style: none;
overflow-y: scroll;
overflow-x: hidden;
flex-grow: 1;
border-radius: 4px;
background: transparent;
@include fancy-scrollbar;
li {
position: relative;
clear: both;
display: inline-block;
padding: 14px;
margin: 0 0 20px 0;
font: 12px/16px 'Noto Sans', sans-serif;
border-radius: 10px;
background-color: $chat-thread-bgd-color;
word-wrap: break-word;
max-width: 81%;
&:before {
position: absolute;
top: 0;
width: $chat-thread-avatar-size;
height: $chat-thread-avatar-size;
border-radius: $chat-thread-avatar-size;
content: '';
background-size: cover;
}
&:after {
position: absolute;
top: $chat-thread-msg-arrow-size;
content: '';
width: 0;
height: 0;
border-top: $chat-thread-msg-arrow-size solid $chat-thread-bgd-color;
}
}
li.other {
animation: show-chat-odd 0.15s 1 ease-in;
-moz-animation: show-chat-odd 0.15s 1 ease-in;
-webkit-animation: show-chat-odd 0.15s 1 ease-in;
float: right;
margin-right: $chat-thread-offset;
color: #0AD5C1;
}
li.other:before {
right: -$chat-thread-offset;
// Placeholder avatar 1
background-image: url(https://github.com/Thatkookooguy.png);
}
li.other:after {
border-right: $chat-thread-msg-arrow-size solid transparent;
right: -$chat-thread-msg-arrow-size;
}
li.self {
animation: show-chat-even 0.15s 1 ease-in;
-moz-animation: show-chat-even 0.15s 1 ease-in;
-webkit-animation: show-chat-even 0.15s 1 ease-in;
float: left;
margin-left: $chat-thread-offset;
color: #0EC879;
}
li.self:before {
left: -$chat-thread-offset;
// Placeholder avatar 2
background-image: url(https://github.com/ortichon.png);
}
li.self:after {
border-left: $chat-thread-msg-arrow-size solid transparent;
left: -$chat-thread-msg-arrow-size;
}
}
.footer {
flex-shrink: 0;
display: flex;
//flex-direction: row-reverse;
padding-top: 10px;
max-height: 90px;
background: transparent;
.text-box {
border-radius: 3px;
background: $chat-thread-bgd-color;
min-height: 100%;
width: 100%;
margin-right: 5px;
color: #0EC879;
overflow-y: auto;
padding: 2px 5px;
@include fancy-scrollbar;
}
}
}
}
// Animation
// --------------------------------------
@keyframes show-chat-even {
0% {
margin-left: -480px;
}
100% {
margin-left: 0;
}
}
@-moz-keyframes show-chat-even {
0% {
margin-left: -480px;
}
100% {
margin-left: 0;
}
}
@-webkit-keyframes show-chat-even {
0% {
margin-left: -480px;
}
100% {
margin-left: 0;
}
}
@keyframes show-chat-odd {
0% {
margin-right: -480px;
}
100% {
margin-right: 0;
}
}
@-moz-keyframes show-chat-odd {
0% {
margin-right: -480px;
}
100% {
margin-right: 0;
}
}
@-webkit-keyframes show-chat-odd {
0% {
margin-right: -480px;
}
100% {
margin-right: 0;
}
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment