Skip to content

Instantly share code, notes, and snippets.

@imnotdev25
Created January 28, 2024 09:33
Show Gist options
  • Save imnotdev25/faa4a908c1fe916810d1d84cd8beea00 to your computer and use it in GitHub Desktop.
Save imnotdev25/faa4a908c1fe916810d1d84cd8beea00 to your computer and use it in GitHub Desktop.
Navvy the navigational ChatBot!
<!-- Currently BROKEN!
Working prototype on meesrutten.me :) -->
<main class="page__main">
<div class="block--background">
<div class="chatbot__overview">
<ul class="chatlist">
<li class="bot__output bot__output--standard">Hey, I'm Navvy!</li>
<li class="bot__output bot__output--standard">I will guide you through Mees' portfolio!</li>
<li class="bot__output bot__output--standard">
<span class="bot__output--second-sentence">You can ask me a bunch of things!</span>
<ul>
<li class="input__nested-list">Something <span class="bot__command">about</span> Mees</li>
<li class="input__nested-list">Mees' <span class="bot__command">best work</span></li>
<li class="input__nested-list">Maybe I could <span class="bot__command">help</span> (for more instructions)</li>
<li class="input__nested-list">Type <span class="bot__command">commands</span> for a list of every command</li>
</ul>
You could also scroll down to see Mees' full portfolio
</li>
</ul>
</div>
<div class="chatbox-area">
<form action="" id="chatform">
<textarea placeholder="Talk to me!" class="chatbox" name="chatbox" resize: "none" minlength="2"></textarea>
<input class="submit-button" type="submit" value="send">
</form>
</div>
<div class="block--background"></div>
</main>

Navvy the navigational ChatBot!

This is a chatbot I made with pure Javascript. It knows a few commands and after some commands you can answer "yes" or "no" to which it will reply

A Pen by Mees on CodePen.

License.

var sendForm = document.querySelector('#chatform'),
textInput = document.querySelector('.chatbox'),
chatList = document.querySelector('.chatlist'),
userBubble = document.querySelectorAll('.userInput'),
botBubble = document.querySelectorAll('.bot__output'),
animateBotBubble = document.querySelectorAll('.bot__input--animation'),
overview = document.querySelector('.chatbot__overview'),
hasCorrectInput,
imgLoader = false,
animationCounter = 1,
animationBubbleDelay = 600,
input,
previousInput,
isReaction = false,
unkwnCommReaction = "I didn't quite get that.",
chatbotButton = document.querySelector(".submit-button")
sendForm.onkeydown = function(e){
if(e.keyCode == 13){
e.preventDefault();
//No mix ups with upper and lowercases
var input = textInput.value.toLowerCase();
//Empty textarea fix
if(input.length > 0) {
createBubble(input)
}
}
};
sendForm.addEventListener('submit', function(e) {
//so form doesnt submit page (no page refresh)
e.preventDefault();
//No mix ups with upper and lowercases
var input = textInput.value.toLowerCase();
//Empty textarea fix
if(input.length > 0) {
createBubble(input)
}
}) //end of eventlistener
var createBubble = function(input) {
//create input bubble
var chatBubble = document.createElement('li');
chatBubble.classList.add('userInput');
//adds input of textarea to chatbubble list item
chatBubble.innerHTML = input;
//adds chatBubble to chatlist
chatList.appendChild(chatBubble)
checkInput(input);
}
var checkInput = function(input) {
hasCorrectInput = false;
isReaction = false;
//Checks all text values in possibleInput
for(var textVal in possibleInput){
//If user reacts with "yes" and the previous input was in textVal
if(input == "yes" || input.indexOf("yes") >= 0){
if(previousInput == textVal) {
console.log("sausigheid");
isReaction = true;
hasCorrectInput = true;
botResponse(textVal);
}
}
if(input == "no" && previousInput == textVal){
unkwnCommReaction = "For a list of commands type: Commands";
unknownCommand("I'm sorry to hear that :(")
unknownCommand(unkwnCommReaction);
hasCorrectInput = true;
}
//Is a word of the input also in possibleInput object?
if(input == textVal || input.indexOf(textVal) >=0 && isReaction == false){
console.log("succes");
hasCorrectInput = true;
botResponse(textVal);
}
}
//When input is not in possibleInput
if(hasCorrectInput == false){
console.log("failed");
unknownCommand(unkwnCommReaction);
hasCorrectInput = true;
}
}
// debugger;
function botResponse(textVal) {
//sets previous input to that what was called
// previousInput = input;
//create response bubble
var userBubble = document.createElement('li');
userBubble.classList.add('bot__output');
if(isReaction == true){
if (typeof reactionInput[textVal] === "function") {
//adds input of textarea to chatbubble list item
userBubble.innerHTML = reactionInput[textVal]();
} else {
userBubble.innerHTML = reactionInput[textVal];
}
}
if(isReaction == false){
//Is the command a function?
if (typeof possibleInput[textVal] === "function") {
// console.log(possibleInput[textVal] +" is a function");
//adds input of textarea to chatbubble list item
userBubble.innerHTML = possibleInput[textVal]();
} else {
userBubble.innerHTML = possibleInput[textVal];
}
}
//add list item to chatlist
chatList.appendChild(userBubble) //adds chatBubble to chatlist
// reset text area input
textInput.value = "";
}
function unknownCommand(unkwnCommReaction) {
// animationCounter = 1;
//create response bubble
var failedResponse = document.createElement('li');
failedResponse.classList.add('bot__output');
failedResponse.classList.add('bot__output--failed');
//Add text to failedResponse
failedResponse.innerHTML = unkwnCommReaction; //adds input of textarea to chatbubble list item
//add list item to chatlist
chatList.appendChild(failedResponse) //adds chatBubble to chatlist
animateBotOutput();
// reset text area input
textInput.value = "";
//Sets chatlist scroll to bottom
chatList.scrollTop = chatList.scrollHeight;
animationCounter = 1;
}
function responseText(e) {
var response = document.createElement('li');
response.classList.add('bot__output');
//Adds whatever is given to responseText() to response bubble
response.innerHTML = e;
chatList.appendChild(response);
animateBotOutput();
console.log(response.clientHeight);
//Sets chatlist scroll to bottom
setTimeout(function(){
chatList.scrollTop = chatList.scrollHeight;
console.log(response.clientHeight);
}, 0)
}
function responseImg(e) {
var image = new Image();
image.classList.add('bot__output');
//Custom class for styling
image.classList.add('bot__outputImage');
//Gets the image
image.src = "/images/"+e;
chatList.appendChild(image);
animateBotOutput()
if(image.completed) {
chatList.scrollTop = chatList.scrollTop + image.scrollHeight;
}
else {
image.addEventListener('load', function(){
chatList.scrollTop = chatList.scrollTop + image.scrollHeight;
})
}
}
//change to SCSS loop
function animateBotOutput() {
chatList.lastElementChild.style.animationDelay= (animationCounter * animationBubbleDelay)+"ms";
animationCounter++;
chatList.lastElementChild.style.animationPlayState = "running";
}
function commandReset(e){
animationCounter = 1;
previousInput = Object.keys(possibleInput)[e];
}
// hlep
var possibleInput = {
// "hlep" : this.help(),
"help" : function(){
responseText("You can type a command in the chatbox")
responseText("Something like &quot;Navvy, please show me Mees&rsquo; best work&quot;")
responseText("Did you find a bug or problem? Tweet me @MeesRttn")
commandReset(0);
return
},
"best work" : function(){
responseText("I will show you Mees' best work!");
responseText("These are his <a href='#animation'>best animations</a>")
responseText("These are his <a href='#projects'>best projects</a>")
responseText("Would you like to see how I was built? (Yes/No)")
commandReset(1);
return
},
"about" : function(){
responseText("This is me, Navvy's maker, Mees Rutten");
responseText("I'm a 22 year old Communication and Multimedia Design student");
responseText("My ambition is to become a great Creative Front-End Developer");
responseText("Would you like to know about Mees' vision? (Yes/No)");
commandReset(2);
return
},
"experience" : function(){
responseText("Mees has previously worked at:");
responseText("Cobra Systems as web- developer / designer");
responseText("BIT Students as web- developer / designer");
responseText("MediaMonks as a junior Front-end Developer");
commandReset(3);
return
},
"hobbies" : function(){
responseText("Mees loves:");
responseText("Coding complicated chatbots");
responseText("Family time");
responseText("Going out with friends");
responseText("Working out");
commandReset(4);
return
},
"interests" : function(){
responseText("Mees loves:");
responseText("Coding complicated chatbots");
responseText("Family time");
responseText("Going out with friends");
responseText("Working out");
commandReset(5);
return
},
"vision" : function(){
responseText("Things I want to learn or do:");
responseText("Get great at CSS & JS animation");
responseText("Create 3D browser experiences");
responseText("Learn Three.js and WebGL");
responseText("Combine Motion Design with Front-End");
commandReset(6);
return
},
"contact" : function(){
responseText("email: <a href='mailto:meesrutten@gmail.com?Subject=Hello%20Mees' target='_top'>send me a message</a>");
responseText("Twitter: <a href='https://twitter.com/meesrttn'>@MeesRttn</a>");
commandReset(7);
return
},
"commands" : function(){
responseText("This is a list of commands Navvy knows:")
responseText("help, best work, about, vision, experience, hobbies / interests, contact, rick roll");
commandReset(8);
return
},
"rick roll" : function(){
window.location.href = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
},
// work experience
}
var reactionInput = {
"best work" : function(){
//Redirects you to a different page after 3 secs
responseText("On this GitHub page you'll find everything about Navvy");
responseText("<a href='https://github.com/meesrutten/chatbot'>Navvy on GitHub</a>")
animationCounter = 1;
return
},
"about" : function(){
responseText("Things I want to learn or do:");
responseText("Get great at CSS & JS animation");
responseText("Create 3D browser experiences");
responseText("Learn Three.js and WebGL");
responseText("Combine Motion Design with Front-End");
animationCounter = 1;
return
}
}
/* https://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
///////////////
// END OF RESET
///////////////
$main-color-1: #2ecc71;
$main-color-2: #27ae60;
$second-color-1: #CC8914;
$background-color: #363636;
$bot-output-delay: 600ms;
@import url('https://fonts.googleapis.com/css?family=Montserrat|Roboto');
*, *:before, *:after {
box-sizing: border-box;
}
body {
overflow-x: hidden;
font-family: 'Roboto', sans-serif;
font-weight: 400;
font-size: 16px;
font-size: 1em;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
line-height: 1.45;
background-color: $background-color;
}
.chatbot__overview {
background-color: $background-color;
display: flex;
flex-flow: row nowrap;
align-content: space-between;
// max-width: 35em;
min-height: 80vh;
max-height: 80vh;
margin: 0 auto;
// background-color: #444;
// border: 1px solid #fff;
padding: 1em;
padding-bottom: 0;
// overflow-y: scroll;
}
.chatbot__overview--container {
}
.chatlist {
font-family: inherit;
font-size: 1em;
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
overflow-x: hidden;
width: 100%;
max-width: 35em;
max-height: 75vh;
margin: 0 auto;
.userInput, .bot__output {
padding: 0.85em;
margin: 0.5em;
max-width: 100%;
background-color: #fff;
border-radius: 5px;
border-bottom: 1px solid #777;
// transition: all 300ms ease-in;
}
.userInput {
text-transform: lowercase;
box-shadow: 1px 1px 2px #666;
border-top: 4px solid $second-color-1;
opacity: 0;
animation-name: animateBubble;
animation-duration: 400ms;
animation-iteration-count: 1;
animation-play-state: running;
animation-fill-mode: forwards;
}
.bot__output {
align-self: flex-start;
box-shadow: -1px 1px 2px #666;
border-top: 4px solid $main-color-2;
// transform-origin: left 50%;
will-change: auto;
height: auto;
opacity: 0;
animation-name: animateBubble;
animation-duration: 400ms;
animation-iteration-count: 1;
animation-play-state: paused;
animation-fill-mode: forwards;
&:last-child {
display: none;
}
}
.bot__command {
// border-bottom: 2px solid $main-color-1;
color: #f5f5f5;
// background-color: $main-color-1;
color: $main-color-2;
font-weight: 600;
padding: 0.1em;
}
.bot__output:nth-child(1){
animation-delay: $bot-output-delay;
animation-play-state: running;
}
.bot__output:nth-child(2){
animation-delay: ($bot-output-delay * 2);
animation-play-state: running;
}
.bot__output:nth-child(3){
animation-delay: ($bot-output-delay * 3);
animation-play-state: running;
}
.bot__output--standard:last-child{
display: block;
}
.bot__output--failed {
display: block !important;
}
.bot__output--second-sentence {
display: block;
}
.bot__outputImage {
max-width: 16em;
height: 12em;
}
}
@keyframes animateBubble {
0%{
transform: translateY(-20%);
opacity: 0;
}
100%{
transform: translateY(0);
opacity: 1;
}
}
.block--background {
// background-color: $main-color-2;
background-color: $background-color;
width: 100vw;
height: 100vh;
}
#chatform {
display: flex;
justify-content: center;
// display: inline-block;
// height: 100%;
width: 80%;
max-width: 35em;
margin: 0 auto;
padding-top: 1em;
font-size: 1em;
font-family: Helvetica;
@media screen and(max-width: 29em) {
width: 90%;
}
}
.chatbox-area {
margin: 0 auto;
position: relative;
bottom: 0;
height: auto;
width: 100%;
}
textarea[name="chatbox"] {
resize: none;
border: 2px solid $main-color-2;
border-right: 0;
// border-bottom: 0;
width: 70%;
background-color: transparent;
color: #fff;
// max-width: 30em;
height: 3em;
margin: 0;
padding: 0.75em;
// float: left;
border-radius: 8px 0px 0px 8px;
font-family: inherit;
font-size: 1em;
&:focus {
outline: none;
border: 2px solid lighten($main-color-2, 15%);
}
}
::-webkit-input-placeholder { /* WebKit, Blink, Edge */
color: #fff;
}
:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
color: #fff;
opacity: 1;
}
::-moz-placeholder { /* Mozilla Firefox 19+ */
color: #fff;
opacity: 1;
}
input[type="submit"] {
-webkit-appearance: none;
appearance: none;
border: 0;
width: 25%;
margin: 0;
background-color: $main-color-2;
color: #fff;
border: 2px solid $main-color-2;
border-left: 0;
border-radius: 0 8px 8px 0;
font-family: inherit;
font-size: 1em;
transition: 200ms all ease-in;
&:hover {
background-color: lighten($main-color-2, 15%);
border-color: lighten($main-color-2, 15%);
color: #fff;
}
}
.input__nested-list {
list-style: disc;
list-style-position: inside;
padding: 0.5em;
&:first-child {
padding-top: 1em;
}
}
.input__nested-link {
color: $main-color-1;
text-decoration: none;
border-bottom: 1px solid $main-color-1;
}
::-webkit-scrollbar
{
width: 0.65em; /* for vertical scrollbars */
height: 0.65em; /* for horizontal scrollbars */
}
::-webkit-scrollbar-track
{
background: rgba(0, 0, 0, 0.1);
}
::-webkit-scrollbar-thumb
{
background: rgba(0, 0, 0, 0.3);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment