Browse Source

Add joke-API;

Add manifest;
Reformatting;
Style commands;
Add feature-toggles;
Edit timeouts;
master
neroignis 5 years ago
parent
commit
12fd6d620b
  1. 8
      app.css
  2. 225
      app.js
  3. BIN
      img/luna.png
  4. 9
      index.html
  5. 16
      manifest/kara.json

8
app.css

@ -63,3 +63,11 @@ body {
.form-button { .form-button {
width: 100%; width: 100%;
} }
.command-message {
color: grey;
}
.command-message::before {
content: '$: ';
}

225
app.js

@ -1,8 +1,15 @@
let kara = new Vue({ let kara = new Vue({
el: '#kara', el: '#kara',
data: { data: {
features: {
changeName: false,
themes: true,
ownReactions: false,
setNameAtStart: true
},
messages: [], messages: [],
lastMessage: null, lastMessage: null,
lastMessageData: {},
name: 'Kara', name: 'Kara',
location: null, location: null,
chatbox: null, chatbox: null,
@ -52,7 +59,9 @@ let kara = new Vue({
}, },
mounted() { mounted() {
this.getSavedData(); this.getSavedData();
this.getBootswatchThemes(); if (this.features.themes) {
this.getBootswatchThemes();
}
this.settingsModal = { this.settingsModal = {
name: this.name, name: this.name,
@ -62,7 +71,10 @@ let kara = new Vue({
if (!this.username || this.username === "null") { if (!this.username || this.username === "null") {
this.initialGreeting(); this.initialGreeting();
this.askForName();
if (this.features.setNameAtStart) {
this.askForName();
}
this.isTyping = false; this.isTyping = false;
} else { } else {
@ -79,6 +91,7 @@ let kara = new Vue({
this.messages.push({ this.messages.push({
body: body, body: body,
bot: bot, bot: bot,
command: body.search('/') === 0,
time: Date.now() time: Date.now()
}) })
}, },
@ -127,31 +140,73 @@ let kara = new Vue({
react(message) { react(message) {
this.isTyping = true; this.isTyping = true;
setTimeout(() => { if (message.search('/') === 0) {
// Check commands setTimeout(() => {
if (this.checkForCommands(message, 'note')) { this.processCommands(message);
let noteToSave = this.checkForCommands(message, 'note');
this.saveNote(noteToSave); this.isTyping = false;
} else if (this.checkForCommands(message, 'clear')) { this.scrollDown();
this.clearChat(); }, 1000);
} else if (this.checkForCommands(message, 'weather')) { } else {
this.checkWeather(); setTimeout(() => {
} else if (this.askedForName === true) { // Check commands
this.setName(message) if (this.askedForName === true) {
} else if (this.takeNote === true) { this.setName(message);
this.saveNote(message) } else if (this.takeNote === true) {
} else { this.saveNote(message);
let answer = this.getAnswer(message); } else {
if (answer) { let answer = this.getAnswer(message);
this.botMessage(answer); if (answer) {
this.botMessage(answer);
}
this.updateStorage();
} }
this.updateStorage(); this.isTyping = false;
this.scrollDown();
}, 1800);
}
},
processCommands(message) {
if (this.checkForCommands(message, 'note')) {
let noteToSave = this.checkForCommands(message, 'note');
this.saveNote(noteToSave);
}
if (this.checkForCommands(message, 'clear')) {
this.clearChat();
}
if (this.checkForCommands(message, 'weather')) {
this.checkWeather()
}
if (this.checkForCommands(message, 'joke')) {
this.tellJoke(this.checkForCommands(message, 'joke'))
}
},
checkForCommands(message, commands) {
if (!Array.isArray(commands)) {
commands = [commands];
}
let commandFound = false;
let parameter = false;
commands.forEach((command) => {
if (commandFound) {
return;
} }
let commandString = '/' + command;
this.isTyping = false; if (message.search(commandString) === 0) {
this.scrollDown(); parameter = message.replace(commandString, '').trim();
}, 2000); commandFound = true;
}
});
return parameter ? parameter : commandFound;
}, },
scrollDown() { scrollDown() {
$('#chat-box').stop().animate({ $('#chat-box').stop().animate({
@ -192,28 +247,6 @@ let kara = new Vue({
return includesAllPhrases; return includesAllPhrases;
}, },
checkForCommands(message, commands) {
if (!Array.isArray(commands)) {
commands = [commands];
}
let commandFound = false;
let parameter = false;
commands.forEach((command) => {
if (commandFound) {
return;
}
let commandString = '/' + command;
if (message.search(commandString) === 0) {
parameter = message.replace(commandString, '').trim();
commandFound = true;
}
});
return parameter ? parameter : commandFound;
},
cleanupMessage(message) { cleanupMessage(message) {
message = message.toLowerCase(); message = message.toLowerCase();
return message.replace('?', '') return message.replace('?', '')
@ -246,13 +279,17 @@ let kara = new Vue({
let phrases = message.split(' '); let phrases = message.split(' ');
let answer = undefined; let answer = undefined;
if (this.lastMessageData.joke && this.includesOneOf(phrases, ['another', 'more'])) {
this.tellJoke(this.lastMessageData.category);
return false;
}
if (this.includesAllOf(phrases, ['change', 'my', 'name'])) { if (this.includesAllOf(phrases, ['change', 'my', 'name'])) {
this.askedForName = true; this.askedForName = true;
return "Please tell me how i should call you."; return "Please tell me how i should call you.";
} }
if ( if (this.includesAllOf(phrases, ['new', 'note']) ||
this.includesAllOf(phrases, ['new', 'note']) ||
this.includesAllOf(phrases, ['new', 'task']) || this.includesAllOf(phrases, ['new', 'task']) ||
this.includesAllOf(phrases, ['save', 'to', 'clipboard']) this.includesAllOf(phrases, ['save', 'to', 'clipboard'])
) { ) {
@ -269,37 +306,43 @@ let kara = new Vue({
return false; return false;
} }
if ( if (this.includesAllOf(phrases, ['knock', 'joke'])) {
this.includesAllOf(phrases, ['whats', 'the', 'time']) || this.tellJoke('knock-knock');
this.includesAllOf(phrases, ['how', 'late']) return false;
}
if (this.includesAllOf(phrases, ['joke']) && this.includesOneOf(phrases, ['coding', 'programming', 'code', 'it'])) {
this.tellJoke('programming');
return false;
}
if (this.includesAllOf(phrases, ['tell', 'joke']) ||
this.includesAllOf(phrases, ['something', 'funny']) ||
this.includesAllOf(phrases, ['cheer', 'me', 'up'])
) { ) {
this.tellJoke('general');
return false;
}
if (this.includesAllOf(phrases, ['whats', 'the', 'time']) || this.includesAllOf(phrases, ['how', 'late'])) {
return "It's " + moment().format('LT'); return "It's " + moment().format('LT');
} }
if ( if (this.includesAllOf(phrases, ['what', 'day', 'it'])) {
this.includesAllOf(phrases, ['what', 'day', 'it'])
) {
return "It's " + moment().format('dddd') + "."; return "It's " + moment().format('dddd') + ".";
} }
if ( if (this.includesAllOf(phrases, ['what', 'date', 'it']) || this.includesAllOf(phrases, ['whats', 'the', 'date'])) {
this.includesAllOf(phrases, ['what', 'date', 'it']) ||
this.includesAllOf(phrases, ['whats', 'the', 'date'])
) {
return "It's " + moment().format('dddd') + ", " + moment().format('MMMM Do YYYY') + "."; return "It's " + moment().format('dddd') + ", " + moment().format('MMMM Do YYYY') + ".";
} }
this.answers.forEach((answerOption) => { this.answers.forEach((answerOption) => {
if (answerOption.includeAll === true) { if (answerOption.includeAll === true) {
if ( if (this.includesAllOf(phrases, answerOption.keywords)) {
this.includesAllOf(phrases, answerOption.keywords)
) {
answer = this.oneOf(answerOption.responses); answer = this.oneOf(answerOption.responses);
} }
} else { } else {
if ( if (this.includesOneOf(phrases, answerOption.keywords)) {
this.includesOneOf(phrases, answerOption.keywords)
) {
answer = this.oneOf(answerOption.responses); answer = this.oneOf(answerOption.responses);
} }
} }
@ -435,14 +478,22 @@ let kara = new Vue({
}, },
clearChat() { clearChat() {
this.messages = []; this.messages = [];
this.botMessage('Chat cleared.'); this.botMessage(this.oneOf([
'Chat cleared.',
'Evidence destroyed.',
'Mind cleared.',
'Uhm.. i think forgot everything we ever talked about.. oops.',
'A fresh start!',
"You've got something to hide? Nevermind, gotcha fam. Chat is cleared now. 🐱👤"
]));
this.updateStorage(); this.updateStorage();
}, },
checkWeather() { checkWeather() {
let vue = this; let vue = this;
if (!vue.location) { if (!vue.location) {
vue.botMessage('Please set your location in the settings.'); vue.botMessage('Please set your location in the settings.');
return; return;
} }
@ -455,8 +506,50 @@ let kara = new Vue({
}) })
.catch(function (error) { .catch(function (error) {
console.log(error); console.log(error);
vue.botMessage('I couldn\'t check the weather for your location.'); vue.botMessage('I couldn\'t check the weather for your location. 🤔');
})
this.updateStorage();
},
tellJoke(category) {
let vue = this;
let categorySet = false;
if (category !== true && category !== false) {
category = category.trim();
categorySet = true;
} else {
category = 'general'
}
let url = 'https://official-joke-api.appspot.com/jokes/' + category + '/random';
axios.get(url)
.then(function (response) {
console.log(response);
let joke = response.data[0];
vue.botMessage(joke.setup);
setTimeout(() => {
vue.botMessage(joke.punchline);
vue.scrollDown();
}, 3500);
vue.lastMessageData = {
joke: true,
category: category
};
}) })
.catch(function (error) {
console.log(error);
if (categorySet) {
vue.botMessage("Sorry, i don't know any jokes about this topic.. 🙄");
} else {
vue.botMessage("I can't remember any jokes right now, sorry. 😢");
}
});
this.updateStorage(); this.updateStorage();
}, },

BIN
img/luna.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

9
index.html

@ -5,6 +5,7 @@
Kara Kara
</title> </title>
<meta charset="utf8"> <meta charset="utf8">
<link rel="manifest" href="manifest/kara.json">
<link href="https://bootswatch.com/4/slate/bootstrap.min.css" rel="stylesheet" type="text/css"/> <link href="https://bootswatch.com/4/slate/bootstrap.min.css" rel="stylesheet" type="text/css"/>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no" name="viewport"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no" name="viewport">
</head> </head>
@ -15,7 +16,7 @@
<div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#settingsModal"> <div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#settingsModal">
<i class="fas fa-sliders-h"></i> <i class="fas fa-sliders-h"></i>
</div> </div>
<div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#addModal"> <div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#addModal" v-if="features.ownReactions">
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
</div> </div>
<div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#noteModal" v-if="notes.length > 0"> <div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#noteModal" v-if="notes.length > 0">
@ -34,7 +35,7 @@
{{ message.body }} {{ message.body }}
<br/> <br/>
</div> </div>
<div class="message user-message float-right" v-else=""> <div :class="'message user-message float-right' + (message.command ? ' command-message' : '')" v-else>
{{ message.body }} {{ message.body }}
<br/> <br/>
</div> </div>
@ -149,7 +150,7 @@
<h5 class="modal-title">Settings</h5> <h5 class="modal-title">Settings</h5>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="form-group"> <div class="form-group" v-if="features.changeName">
<label for="name">What's my name?</label> <label for="name">What's my name?</label>
<input type="text" class="form-control" id="name" v-model="settingsModal.name"> <input type="text" class="form-control" id="name" v-model="settingsModal.name">
</div> </div>
@ -161,7 +162,7 @@
<label for="location">What city do you live in? <small class="text-muted">(for weather-reports only)</small> </label> <label for="location">What city do you live in? <small class="text-muted">(for weather-reports only)</small> </label>
<input type="text" class="form-control" id="location" v-model="settingsModal.location"> <input type="text" class="form-control" id="location" v-model="settingsModal.location">
</div> </div>
<div class="form-group"> <div class="form-group" v-if="features.themes">
<label for="theme">Pick a theme</label> <label for="theme">Pick a theme</label>
<select name="theme" class="form-control" id="theme" v-model="activeTheme" @change="updateStorage()"> <select name="theme" class="form-control" id="theme" v-model="activeTheme" @change="updateStorage()">
<option v-for="theme in themes" :value="theme.name.toLowerCase()" v-text="theme.name"></option> <option v-for="theme in themes" :value="theme.name.toLowerCase()" v-text="theme.name"></option>

16
manifest/kara.json

@ -0,0 +1,16 @@
{
"short_name": "Kara",
"name": "Kara",
"icons": [
{
"src": "img/luna.png",
"type": "image/png",
"sizes": "256x256"
}
],
"start_url": "/kara/",
"background_color": "#383838",
"display": "standalone",
"scope": "/kara/",
"theme_color": "#383838"
}
Loading…
Cancel
Save