Compare commits

..

32 Commits

Author SHA1 Message Date
Nero 9ca05db5e4 Change Todo, remove code 5 years ago
Nero cf16ae157c padding for chatbox due to scrollbar 5 years ago
Nero fcf235c9ce Readd command not found with extra flag; add /66 5 years ago
Nero a8bdb87065 http to https for weather API 5 years ago
Nero cf50acf711 Remove 'Command not found' due to error with ajax-commands 5 years ago
Nero f6180bb23f lowercase keywords 5 years ago
Nero 38047b03cf Fetch reactions in interval 5 years ago
Nero 54a9e84834 Add command not found 5 years ago
Nero Ignis 7f15a43156 Completion of documentation; 5 years ago
Nero Ignis 2f020f2f62 Add documentation.md for rendering in modal; 5 years ago
Nero Ignis cbff487a0d Add lyrics command; message-container & more; 5 years ago
Nero Ignis f54f119026 Add animal pictures & facts; 5 years ago
Nero 6a7b8cc3d7 Apply changes from before revert. 5 years ago
Nero e341da7dc1 Rename notes to todos 5 years ago
stingl f52515b92d Revert "she learned to talk today." 5 years ago
stingl da4d4dc650 Revert "/say command" 5 years ago
stingl 4fff3b8d51 Revert "Rename notes to todos" 5 years ago
stingl 2c4da7abce Revert "remove checkboxes" 5 years ago
stingl 33225b44c0 Revert "remove checkboxes" 5 years ago
Nero 7ae3d4ae4f remove checkboxes 5 years ago
Nero 32bad6d2fe remove checkboxes 5 years ago
Nero 52dbc551c8 Rename notes to todos 5 years ago
neroignis@gmail.com a23a4ce5cb /say command 5 years ago
neroignis@gmail.com 69aef067c6 she learned to talk today. 5 years ago
Nero Ignis c36f1a2d5b Missing : 5 years ago
Nero Ignis 13a12fd8b5 Add lightbox; 5 years ago
Nero Ignis d5905f8977 Dice images; 5 years ago
Nero Ignis 67dfb3fdea Style for dice; 5 years ago
Nero Ignis 9ba484af2c Add chat-interactions for new games; 5 years ago
Nero Ignis a38b8dde8e Add trivia-quiz & jeopardy commands; 5 years ago
Nero Ignis 0aa4303097 Make image-messages smaller; 5 years ago
Nero Ignis 51228ae534 Add new api-functions for testing; 5 years ago
  1. 1
      .gitignore
  2. 2
      README.md
  3. 93
      addReactions.html
  4. 85
      addReponse.js
  5. 100
      app.css
  6. 574
      app.js
  7. BIN
      img/luna.png
  8. 182
      index.html
  9. 16
      manifest/kara.json

1
.gitignore vendored

@ -1 +0,0 @@ @@ -1 +0,0 @@
.idea

2
README.md

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
Kara has been moved to luna-development core repository.
This repository is only for issues.

93
addReactions.html

@ -1,93 +0,0 @@ @@ -1,93 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>
Kara - Add reponses
</title>
<meta charset="utf8">
<link rel="icon" href="/favicon.ico">
<link rel="manifest" href="manifest/kara.json">
<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">
</head>
<body>
<div class="container-fluid" id="kara">
<div id="kara-banner" class="bg-dark text-light">
<img src="/img/logo/luna/icon.ico" class="header-logo" alt="logo-header"/>
{{ this.name }}
</div>
<div class="row" id="addForm">
<div class="col">
<h5>Add Reaction</h5>
<div class="form-group">
<label for="includeAll">Message must include all search-terms</label>
<input type="checkbox" id="includeALl" v-model="addModal.includeAll">
</div>
<div class="form-group">
<label for="keywords">Keywords (separated with comma)</label>
<input type="text" id="keywords" v-model="addModal.keywords" class="form-control">
</div>
<div class="form-group">
<label>Responses</label>
<small>(Wildcards: $username$, $botname$)</small>
<template v-for="(key, responseOption) in addModal.responses">
<input type="text" v-model="addModal.responses[responseOption]" class="form-control response-input">
</template>
<div class="float-right">
<button class="btn-sm btn-success" @click="addResponseToInput">+</button>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" @click="addNewReaction">Add
</button>
</div>
</div>
<link rel="stylesheet"
:href="'https://maxcdn.bootstrapcdn.com/bootswatch/4.3.1/' + activeTheme + '/bootstrap.min.css'">
<link href="app.css" rel="stylesheet" type="text/css"/>
</div>
<script src="https://kit.fontawesome.com/b54a4cceff.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="addReponse.js"></script>
<!-- JavaScript -->
<script src="//cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/alertify.min.js"></script>
<!-- CSS -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/alertify.min.css"/>
<!-- Default theme -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/themes/default.min.css"/>
<!-- Semantic UI theme -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/themes/semantic.min.css"/>
<!-- Bootstrap theme -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/themes/bootstrap.min.css"/>
<!--
RTL version
-->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/alertify.rtl.min.css"/>
<!-- Default theme -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/themes/default.rtl.min.css"/>
<!-- Semantic UI theme -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/themes/semantic.rtl.min.css"/>
<!-- Bootstrap theme -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/themes/bootstrap.rtl.min.css"/>
</body>
</html>

85
addReponse.js

@ -1,85 +0,0 @@ @@ -1,85 +0,0 @@
let responses = new Vue({
el: '#kara',
data: {
name: 'Kara',
activeTheme: 'slate',
addModal: {
includeAll: false,
keywords: 'keyword',
responses: [
'Answer #1'
]
},
defaultAddModal: {
includeAll: false,
keywords: 'keyword',
responses: [
'Answer #1'
]
}
},
mounted() {
this.addModal = this.defaultAddModal;
},
methods: {
addMessage(body, bot, me = false) {
this.messages.push({
body: body,
bot: bot,
command: body.search('/') === 0,
me: me,
time: Date.now()
})
},
addResponseToInput() {
this.addModal.responses.push('');
},
addNewReaction() {
let includeAll = this.addModal.includeAll;
let keywords = this.addModal.keywords.split(',');
let responses = this.addModal.responses;
let newReaction = {
includeAll: includeAll,
keywords: keywords,
responses: responses
};
axios.post('/reactions/create', {
reaction: newReaction
}).then((response) => {
alertify.notify('Reaction saved!', 'success');
this.addModal = this.defaultAddModal;
}).catch((error) => {
console.log(error);
alertify.notify(error, 'danger');
});
},
cleanupMessage(message) {
message = message.toLowerCase();
return message.replace('?', '')
.replace('!', '')
.replace('.', '')
.replace(',', '')
.replace('-', '')
.replace('_', '')
.replace('#', '')
.replace('\'', '')
.replace('"', '')
.replace('+', '')
.replace('*', '')
.replace('§', '')
.replace('$', '')
.replace('%', '')
.replace('&', '')
.replace('/', '')
.replace('(', '')
.replace(')', '')
.replace('=', '')
.replace('\\', '')
.replace('@', '')
.replace('~', '')
.replace('…', '');
}
}
});

100
app.css

@ -1,100 +0,0 @@ @@ -1,100 +0,0 @@
body {
margin: 15px;
padding: 0;
}
#kara {
margin: 0;
padding: 0;
width: auto;
}
@media (min-width: 40em) {
#kara,
#kara-banner,
#chatbox-wrapper {
margin-left: auto;
margin-right: auto;
padding: 0;
width: 40em;
}
}
.message {
color: black;
padding: 10px;
margin-bottom: 5px;
min-width: 55%;
max-width: 80%;
}
.bot-message {
border-radius: 0 15px 15px 15px;
background-color: lightgreen;
}
.user-message {
border-radius: 15px 0 15px 15px;
background-color: lightblue;
}
#chat-box {
margin-top: 4em;
overflow-y: scroll;
height: 65vh;
padding-bottom: 2em;
}
#chatbox-wrapper {
position: fixed;
padding: 1em;
bottom: 0;
left: 0;
right: 0;
}
#kara-banner {
position: fixed;
height: 3.2em;
top: 0;
left: 0;
right: 0;
text-align: center;
padding: 0.7em;
}
#kara-banner .btn, .add-response-input-button {
margin-top: -0.3em;
}
.response-input {
margin-bottom: 3px;
}
.form-button {
width: 100%;
}
.command-message {
color: grey;
}
.command-message::before {
content: '$: ';
}
.header-logo {
max-height: 32px;
max-width: 32px;
width: 32px;
height: 32px;
margin-right: 5px;
}
.me-message {
background-color: orange;
}
#addForm {
margin-top: 60px;
}

574
app.js

@ -1,574 +0,0 @@ @@ -1,574 +0,0 @@
let kara = new Vue({
el: '#kara',
data: {
features: {
changeName: false,
themes: false,
setNameAtStart: true
},
messages: [],
lastMessage: null,
lastMessageData: {},
name: 'Kara',
location: null,
chatbox: null,
isTyping: false,
askedForName: false,
takeNote: false,
username: '',
themes: null,
activeTheme: 'slate',
addModal: {
includeAll: false,
keywords: '',
responses: [
'Answer #1'
]
},
settingsModal: {
name: null,
username: null,
location: ''
},
notes: [],
reactions: []
},
mounted() {
this.getSavedData();
this.getReactions();
if (this.features.themes) {
this.getBootswatchThemes();
}
this.settingsModal = {
name: this.name,
username: this.username,
location: this.location
};
if (!this.username || this.username === "null") {
this.initialGreeting();
if (this.features.setNameAtStart) {
this.askForName();
}
this.isTyping = false;
} else {
this.welcomeBack();
}
document.getElementById('chatinput').focus();
document.title = this.name;
this.scrollDown();
},
methods: {
// Initial
initialGreeting() {
this.botMessage(
this.oneOf(
[
"Hi! I'm " + this.name + ". :)",
"Hi, nice to meet you! My name is " + this.name + ". :)"
]
)
);
},
welcomeBack() {
this.botMessage(
this.oneOf(
[
"Hi! Haven't heard of you in a while. :)",
"Welcome back! :)",
"Hey :) Good to see you :)",
]
)
);
},
// Name
askForName() {
this.botMessage(
this.oneOf([
'May i ask for your name?',
'Whats your name? :)',
'How can i call you?',
'How did your developers call you? :)'
])
);
this.askedForName = true;
},
setName(message) {
this.username = message.trim();
this.settingsModal.username = this.username;
this.askedForName = false;
this.botMessage(
this.oneOf([
"That's a beautiful name!",
"Okay, i'll call you " + this.username + " from now on :)",
"Nice to meet you, " + this.username + ". :D"
])
)
this.updateStorage();
},
// Messages / Chat
addMessage(body, bot, me = false) {
this.messages.push({
body: body,
bot: bot,
command: body.search('/') === 0,
me: me,
time: Date.now()
})
},
botMessage(body) {
this.addMessage(body, true);
},
userMessage(body) {
this.addMessage(body, false);
this.lastMessage = body;
this.updateStorage();
},
sendMessage() {
if (this.chatbox.trim() === '') {
return false;
}
if (this.chatbox.search('/me') !== 0) {
this.userMessage(this.chatbox);
}
this.scrollDown();
this.react(this.chatbox);
this.chatbox = '';
},
meMessage(message) {
this.addMessage(this.username + ' ' + message, false, true);
this.react(message, true);
},
react(message, recursive = false) {
this.isTyping = true;
if (message.search('/') === 0 && !recursive) {
setTimeout(() => {
this.processCommands(message);
this.isTyping = false;
this.scrollDown();
}, 1000);
} else {
setTimeout(() => {
// Check commands
if (this.askedForName === true) {
this.setName(message);
} else if (this.takeNote === true) {
this.saveNote(message);
} else {
let answer = this.getReaction(message);
if (answer) {
this.botMessage(answer);
}
this.updateStorage();
}
this.isTyping = false;
this.scrollDown();
}, 1800);
}
},
getReaction(message) {
message = this.cleanupMessage(message);
let keywords = message.split(' ');
let answer = undefined;
if (this.lastMessageData.joke && this.includesOneOf(keywords, ['another', 'more'])) {
this.tellJoke(this.lastMessageData.category);
return false;
}
this.lastMessageData = {};
if (this.includesAllOf(keywords, ['change', 'my', 'name'])) {
this.askedForName = true;
return "Please tell me how i should call you.";
}
if (this.includesAllOf(keywords, ['new', 'note']) ||
this.includesAllOf(keywords, ['new', 'task']) ||
this.includesAllOf(keywords, ['take', 'note']) ||
this.includesAllOf(keywords, ['save', 'to', 'clipboard'])
) {
this.takeNote = true;
return this.oneOf([
"What do you wan't me to save for you?",
"Tell me what you wan't to save.",
"What is it you wan't to save?",
]);
}
if (this.includesAllOf(keywords, ['clear', 'chat'])) {
this.clearChat();
return false;
}
if (this.includesAllOf(keywords, ['weather']) &&
this.includesOneOf(keywords, ['how', 'whats'])
) {
this.checkWeather();
return false;
}
if (this.includesAllOf(keywords, ['knock', 'joke'])) {
this.tellJoke('knock-knock');
return false;
}
if (this.includesAllOf(keywords, ['joke']) && this.includesOneOf(keywords, ['coding', 'programming', 'code', 'it'])) {
this.tellJoke('programming');
return false;
}
if (this.includesAllOf(keywords, ['tell', 'joke']) ||
this.includesAllOf(keywords, ['something', 'funny']) ||
this.includesAllOf(keywords, ['cheer', 'me', 'up'])
) {
this.tellJoke('general');
return false;
}
if (this.includesAllOf(keywords, ['whats', 'the', 'time']) || this.includesAllOf(keywords, ['how', 'late'])) {
return "It's " + moment().format('LT');
}
if (this.includesAllOf(keywords, ['what', 'day', 'it'])) {
return "It's " + moment().format('dddd') + ".";
}
if (this.includesAllOf(keywords, ['what', 'date', 'it']) || this.includesAllOf(keywords, ['whats', 'the', 'date'])) {
return "It's " + moment().format('dddd') + ", " + moment().format('MMMM Do YYYY') + ".";
}
this.reactions.forEach((reactionOption) => {
if (reactionOption.includeAll === true) {
if (this.includesAllOf(keywords, reactionOption.keywords)) {
answer = this.oneOf(reactionOption.responses);
}
} else {
if (this.includesOneOf(keywords, reactionOption.keywords)) {
answer = this.oneOf(reactionOption.responses);
}
}
});
if (answer) {
return answer;
}
return 'I don\'t know what to say..';
},
// Forms
saveSettings() {
this.name = this.settingsModal.name;
this.username = this.settingsModal.username;
this.location = this.settingsModal.location;
this.updateStorage();
// this.botMessage('Settings saved! :)');
this.scrollDown();
},
// Commands
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'))
}
if (this.checkForCommands(message, 'me')) {
this.meMessage(this.checkForCommands(message, 'me'))
}
},
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;
},
checkWeather() {
let vue = this;
if (!vue.location) {
vue.botMessage('Please set your location in the settings. ⚙');
return;
}
let city = this.location.toLowerCase();
let url = 'http://api.openweathermap.org/data/2.5/weather?q=' + city + '&appid=8a1aa336da8899c1038bf6bd808d8961&units=metric';
axios.get(url)
.then(function (response) {
vue.botMessage('In ' + response.data.name + ' it\'s ' + response.data.main.temp.toFixed() + '°C with ' + response.data.weather[0].description + '.');
})
.catch(function (error) {
alertify.notify(error, 'danger');
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) {
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();
},
// Notes
saveNote(message) {
this.takeNote = false;
this.notes.push({
time: moment(),
body: message,
checked: false
});
this.updateStorage();
this.botMessage(
this.oneOf([
"Saved! :)",
"You can read and check your notes in the clipboard-section. :)"
])
)
},
clearNotes() {
this.notes = [];
this.botMessage(
this.oneOf([
"Notes cleared. 🚮"
])
);
this.updateStorage();
},
// LocalStorage
getSavedData() {
let savedName = localStorage.getItem('name');
this.name = savedName ? savedName : this.name;
let savedUsername = localStorage.getItem('username');
this.username = savedUsername ? savedUsername : null;
let savedActiveTheme = localStorage.getItem('activeTheme');
this.activeTheme = savedActiveTheme ? savedActiveTheme : 'slate';
let savedMessages = JSON.parse(localStorage.getItem('messages'));
this.messages = savedMessages ? savedMessages : [];
let savedNotes = JSON.parse(localStorage.getItem('notes'));
this.notes = savedNotes ? savedNotes : [];
let savedLastMessage = JSON.parse(localStorage.getItem('lastMessage'));
this.lastMessage = savedLastMessage ? savedLastMessage : null;
let savedLocation = JSON.parse(localStorage.getItem('location'));
this.location = savedLocation ? savedLocation : null;
this.scrollDown();
},
updateStorage() {
localStorage.setItem('name', this.name);
localStorage.setItem('username', this.username);
localStorage.setItem('activeTheme', this.activeTheme);
localStorage.setItem('messages', JSON.stringify(this.messages));
localStorage.setItem('answers', JSON.stringify(this.reactions));
localStorage.setItem('notes', JSON.stringify(this.notes));
localStorage.setItem('lastMessage', JSON.stringify(this.lastMessage));
localStorage.setItem('location', JSON.stringify(this.location));
},
clearStorage() {
localStorage.clear();
location.reload();
},
// Utility
scrollDown() {
$('#chat-box').stop().animate({
scrollTop: ($('#chat-box')[0].scrollHeight * 10)
}, 800);
},
oneOf(answers) {
let amountOfAnswers = answers.length;
let randomIndex = Math.floor(Math.random() * (amountOfAnswers));
return this.convertWildcards(answers[randomIndex]);
},
convertWildcards(message) {
message = message.replace('$name$', this.username);
message = message.replace('$botname$', this.name);
return message;
},
cleanupMessage(message) {
message = message.toLowerCase();
return message.replace('?', '')
.replace('!', '')
.replace('.', '')
.replace(',', '')
.replace('-', '')
.replace('_', '')
.replace('#', '')
.replace('\'', '')
.replace('"', '')
.replace('+', '')
.replace('*', '')
.replace('§', '')
.replace('$', '')
.replace('%', '')
.replace('&', '')
.replace('/', '')
.replace('(', '')
.replace(')', '')
.replace('=', '')
.replace('\\', '')
.replace('@', '')
.replace('~', '')
.replace('…', '');
},
clearChat() {
this.messages = [];
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();
},
includesOneOf(keywords, wordsToSearch) {
let includes = false;
wordsToSearch.forEach((searchWord) => {
if (keywords.includes(searchWord)) {
includes = true;
}
})
return includes;
},
includesAllOf(keywords, wordsToSearch) {
let includesAllkeywords = true;
wordsToSearch.forEach((searchWord) => {
if (!keywords.includes(searchWord)) {
includesAllkeywords = false;
}
})
return includesAllkeywords;
},
// Ajax calls for saving/receiving reactions & themes
getBootswatchThemes() {
let vue = this;
axios.get('https://bootswatch.com/api/4.json')
.then(function (response) {
vue.themes = response.data.themes;
})
.catch(function (error) {
console.log(error);
})
},
getReactions() {
let vue = this;
axios.get('/reactions/get').then((response) => {
response.data.forEach((reaction) => {
vue.reactions.push(JSON.parse(reaction.reaction));
});
}).catch((error) => {
console.log(error);
});
}
}
})

BIN
img/luna.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

182
index.html

@ -1,182 +0,0 @@ @@ -1,182 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>
Kara
</title>
<meta charset="utf8">
<link rel="icon" href="/favicon.ico">
<link rel="manifest" href="manifest/kara.json">
<link href="https://bootswatch.com/4/slate/bootstrap.min.css" rel="stylesheet" type="text/css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/alertify.min.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/themes/default.min.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/css/themes/bootstrap.min.css"/>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no" name="viewport">
</head>
<body>
<div class="container-fluid" id="kara">
<div id="kara-banner" class="bg-dark text-light">
<img src="/img/logo/luna/icon.ico" class="header-logo" alt="logo-header"/>
<div class="float-right">
<div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#settingsModal">
<i class="fas fa-sliders-h"></i>
</div>
<div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#noteModal" v-if="notes.length > 0">
<i class="fas fa-clipboard"></i>
</div>
<div class="btn btn-sm btn-secondary" @click="scrollDown()">
<i class="fas fa-chevron-down"></i>
</div>
</div>
{{ this.name }}
</div>
<div id="chat-box">
<template v-for="message in messages">
<div class="message bot-message float-left" v-if="message.bot">
{{ message.body }}
<br/>
</div>
<div :class="'message user-message float-right' + (message.command ? ' command-message' : '') + (message.me ? ' me-message' : '')" v-else>
{{ message.body }}
<br/>
</div>
</template>
<div class="message bot-message typing float-left" v-if="isTyping">
<div class="spinner-grow text-secondary" role="status">
<span class="sr-only">
Loading...
</span>
</div>
<div class="spinner-grow text-secondary" role="status">
<span class="sr-only">
Loading...
</span>
</div>
<div class="spinner-grow text-secondary" role="status">
<span class="sr-only">
Loading...
</span>
</div>
</div>
</div>
<div id="chatbox-wrapper" class="bg-dark">
<input class="form-control"
id="chatinput"
type="text"
v-model="chatbox"
v-on:keyup.enter="sendMessage()"
v-on:keyup.38="chatbox = lastMessage"
v-on:keyup.40="chatbox = ''"
required autofocus>
</div>
<div class="modal fade" id="noteModal" tabindex="-1" role="dialog" aria-labelledby="noteModal" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Notes</h5>
<div class="float-right">
<button class="btn btn-sm btn-secondary" @click="clearNotes">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
<div class="modal-body" style="max-height: 800px; overflow-y: scroll">
<ul class="list-group">
<li class="list-group-item" v-for="note in notes" v-if="!note.checked">
<span class="float-right">
<input type="checkbox" v-model="note.checked" @change="updateStorage()"/>
</span>
{{ note.body }}
</li>
</ul>
<hr/>
<ul class="list-group">
<li class="list-group-item" v-for="note in notes" v-if="note.checked">
<span class="float-right">
<input type="checkbox" v-model="note.checked" @change="updateStorage()"/>
</span>
<span style="text-decoration: line-through;">{{ note.body }}</span>
</li>
</ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="settingsModal" tabindex="-1" role="dialog" aria-labelledby="settingsModal" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Settings</h5>
</div>
<div class="modal-body">
<div class="form-group" v-if="features.changeName">
<label for="name">What's my name?</label>
<input type="text" class="form-control" id="name" v-model="settingsModal.name">
</div>
<div class="form-group" v-if="username !== null">
<label for="username">What's your name?</label>
<input type="text" class="form-control" id="username" v-model="settingsModal.username">
</div>
<div class="form-group">
<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">
</div>
<div class="form-group" v-if="features.themes">
<label for="theme">Pick a theme</label>
<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>
</select>
</div>
<div class="form-group">
<label>Data</label>
<div class="row">
<div class="col-sm-6">
<button @click="clearChat()" class="btn btn-warning form-button" data-dismiss="modal">
Delete chat
</button>
</div>
<div class="col-sm-6">
<button @click="clearStorage()" class="btn btn-warning form-button">
Delete everything
</button>
</div>
</div>
</div>
<div class="form-group">
<div class="float-right">
<i class="fa fa-code" aria-hidden="true"></i> App by <a href="/">Luna Development</a>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" @click="saveSettings()">Save</button>
</div>
</div>
</div>
</div>
<link rel="stylesheet" :href="'https://maxcdn.bootstrapcdn.com/bootswatch/4.3.1/' + activeTheme + '/bootstrap.min.css'">
<link href="app.css" rel="stylesheet" type="text/css"/>
</div>
<script src="https://kit.fontawesome.com/b54a4cceff.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/alertifyjs@1.13.1/build/alertify.min.js"></script>
<script src="app.js">
</script>
</body>
</html>

16
manifest/kara.json

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