<main id="main">
<div id="peekobot-container">
<div id="peekobot"></div>
</div>
</main>
:root {
--peekobot-height: 80vh;
--peekobot-avatar: url("https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&s=a72ca28288878f8404a795f39642a46f");
}
#peekobot-container {
border: 1px solid hsl(0, 0%, 90%);
border-radius: 12px;
box-shadow: 2px 2px 5px hsl(0, 0%, 60%);
padding: 1rem;
overflow: scroll;
scroll-behavior: smooth;
height: var(--peekobot-height);
width: 50%;
margin: 0 0 0 auto;
}
.chat-response,
.chat-ask {
opacity: 0;
transform: translateY(-50%);
transition: all 0.3s 0.3s;
border-radius: 12px;
background-color: hsl(0, 0%, 90%);
padding: 0.5rem 0.7rem;
line-height: 1.4;
color: black;
width: 80%;
margin-bottom: 0.5rem;
}
.chat-response {
margin-left: 22px;
position: relative;
}
.chat-response:before {
display: block;
content: "";
width: 24px;
height: 24px;
position: absolute;
left: -26px;
top: 6px;
background-image: var(--peekobot-avatar);
background-color: #999;
background-repeat: no-repeat;
background-size: 100%;
border-radius: 100%;
}
.chat-ask {
background-color: hsl(207, 96%, 55%);
margin-right: 0;
margin-left: auto;
color: hsl(0, 0%, 100%);
}
.choices {
opacity: 0; /* Set to active to show */
transform: translateY(-50%); /* Set to activated to move down */
transition: all 0.3s 0.3s;
transition: opacity 0.3s 0.3s;
margin-top: 0.5rem;
margin-left: 22px;
}
.choice {
display: inline-block;
outline: none;
border: 1px solid hsl(0, 0%, 0%);
padding: 0.3rem 0.8rem;
background-color: hsl(0, 0%, 100%);
border-radius: 1rem;
font-size: 0.9rem;
line-height: 1.3;
margin-bottom: 0.5rem;
margin-right: 0.5rem;
text-decoration: none;
color: inherit;
}
.choice:disabled {
color: hsl(0, 0%, 80%);
border-color: hsl(0, 0%, 80%);
}
.activated {
opacity: 1;
transform: translateY(0);
}
const chat = {
1: {
text: "こんにちは!お困りですか?",
options: [
{
text: "なにこれ?",
next: 2
}
]
},
2: {
text: "Peekobotというスクリプトを紹介する記事です。Peekobotはシンプルな選択式チャットボットフレームワークです",
next: 3
},
3: {
text:
"ユーザーに選択してもらう形で成り立つ対話コンテンツで、目的の場所への誘導を促します",
options: [
{
text: "よくわかった!",
next: 4
},
{
text: "ちょっと何言ってるか分からない",
next: 5
}
]
},
4: {
text:
"頭いいですね!簡単なものなので質問も簡単なものくらいしか出来ません。詳しくはGithubをご覧ください",
next: 7
},
5: {
text: "サンドイッチマン好きですか?",
next: 6
},
6: {
text: "サンドイッチマンの動画を紹介しますね",
options: [
{
text: "サンドの公式Youtubeへどうぞ!",
url:
"https://www.youtube.com/playlist?list=PLe8FGQbLGisnnab5M-2o88p4SAKPVb1RV"
}
]
},
7: {
text: "ライセンスはMITとのことです",
options: [
{
text: "GitHubへ",
url: "https://github.com/peekobot/peekobot"
}
]
}
};
const bot = function() {
const peekobot = document.getElementById("peekobot");
const container = document.getElementById("peekobot-container");
const sleep = function(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
};
const scrollContainer = function() {
container.scrollTop = container.scrollHeight;
};
const insertNewChatItem = function(elem) {
container.insertBefore(elem, peekobot);
scrollContainer();
//debugger;
elem.classList.add("activated");
};
const printResponse = async function(step) {
const response = document.createElement("div");
response.classList.add("chat-response");
response.innerHTML = step.text;
insertNewChatItem(response);
await sleep(1500);
if (step.options) {
const choices = document.createElement("div");
choices.classList.add("choices");
step.options.forEach(function(option) {
const button = document.createElement(option.url ? "a" : "button");
button.classList.add("choice");
button.innerHTML = option.text;
if (option.url) {
button.href = option.url;
} else {
button.dataset.next = option.next;
}
choices.appendChild(button);
});
insertNewChatItem(choices);
} else if (step.next) {
printResponse(chat[step.next]);
}
};
const printChoice = function(choice) {
const choiceElem = document.createElement("div");
choiceElem.classList.add("chat-ask");
choiceElem.innerHTML = choice.innerHTML;
insertNewChatItem(choiceElem);
};
const disableAllChoices = function() {
const choices = document.querySelectorAll(".choice");
choices.forEach(function(choice) {
choice.disabled = "disabled";
});
return;
};
const handleChoice = async function(e) {
if (!e.target.classList.contains("choice") || "A" === e.target.tagName) {
return;
}
e.preventDefault();
const choice = e.target;
disableAllChoices();
printChoice(choice);
scrollContainer();
await sleep(1500);
if (choice.dataset.next) {
printResponse(chat[choice.dataset.next]);
}
// Need to disable buttons here to prevent multiple choices
};
const init = function() {
container.addEventListener("click", handleChoice);
printResponse(chat[1]);
};
init();
};
bot();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.