diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6503c41 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,134 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +gia.nebieridze@gmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..06b47f6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,3 @@ +Looks like there's already a license file for this project. +[?25l[2K[1G[36m?[39m [1mDo you want to replace it?[22m [90m›[39m [90m(y/N)[39m[2K[1G[2K[1G[32m✔[39m [1mDo you want to replace it?[22m [90m…[39m no +[?25hExiting... diff --git a/README.md b/README.md new file mode 100644 index 0000000..68183f2 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# scrpt diff --git a/package.json b/package.json new file mode 100644 index 0000000..1fa4750 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "ai-widget", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/src/scrpt.js b/src/scrpt.js new file mode 100644 index 0000000..3ba9789 --- /dev/null +++ b/src/scrpt.js @@ -0,0 +1,327 @@ +const xPositions = ['left', 'right']; +const yPositions = ['top', 'bottom']; +const nm = 'scrpt'; +const chatWidth = '400px'; +const domain = 'http://161.35.71.150'; +class Scrpt { + loadInterval; + constructor({ position = 'bottom-right', appName = '' } = {}) { + this.position = this.getPosition(position); + this.open = false; + this.inputText = ''; + this.appName = appName; + + if (!position.includes('-')) { + throw new Error("position must include - symbol. for example bottom-right"); + } + if (!yPositions.includes(position.split('-')[0])) { + throw new Error("y position must be top or bottom"); + } + if (!xPositions.includes(position.split('-')[1])) { + throw new Error("x position must be left or right"); + } + if (appName === '') { + throw new Error("invalid app name"); + } + this.getChatInitialData(appName).then(_ => { + this.initialize(); + }); + this.createStyles(); + } + + getPosition(position) { + const [y, x] = position.split('-'); + return { + [y]: '40px', + [x]: '40px', + }; + } + + initialize() { + const container = document.createElement('div'); + container.style.position = 'fixed'; + container.style.zIndex = '9999'; + Object.keys(this.position) + .forEach(key => container.style[key] = this.position[key]); + + document.body.appendChild(container); + + const buttonContainer = document.createElement('div'); + buttonContainer.classList.add(`${nm}-button-container`); + + const chatIcon = document.createElement('span'); + chatIcon.innerHTML = + ``; + chatIcon.classList.add(`${nm}-icon`); + this.chatIcon = chatIcon; + + const closeIcon = document.createElement('span'); + closeIcon.innerHTML = ``; + closeIcon.classList.add(`${nm}-icon`, `${nm}-hidden`); + this.closeIcon = closeIcon; + + this.chatContainer = document.createElement('div'); + this.chatContainer.classList.add(`${nm}-hidden`, `${nm}-chat-container`); + this.chatContainer.style.width = chatWidth; + + this.createChatContainerContent(); + + buttonContainer.appendChild(this.chatIcon); + buttonContainer.appendChild(this.closeIcon); + + buttonContainer.addEventListener('click', this.toggleOpen.bind(this)); + + container.appendChild(this.chatContainer); + container.appendChild(buttonContainer); + this.chatContent.innerHTML += this.chatStripe(true, this.welcomeMessage, ''); + } + + createStyles() { + const styleTag = document.createElement('style'); + document.head.appendChild(styleTag); + styleTag.innerHTML = ` + ${nm}-button-container,${nm}-scrpt-header{background:linear-gradient(to bottom right,#4294e3,#8f12fd)}${nm}-clearfix::after{content:"";clear:both;display:table}${nm}-icon{cursor:pointer;width:100%;position:absolute;top:11px;left:13px;transition:transform .3s;color:#fff}${nm}-hidden{transform:scale(0)}${nm}-button-container{width:70px;height:70px;border-radius:50%}${nm}-chat-container{box-shadow:0 0 18px 8px rgba(0,0,0,.1);right:-25px;bottom:75px;position:absolute;transition:max-height .2s;background-color:#fff;border-radius:10px}${nm}-chat-container.hidden{max-height:0}${nm}-scrpt-header{display:inline-block;width:100%;margin:0;padding:10px;color:#fff;border-top-left-radius:10px;border-top-right-radius:10px}${nm}-chat-container form input{padding:20px;display:inline-block;width:calc(100% - 50px);border:0;background-color:#f7f7f7}${nm}-chat-container form input:focus{outline:0}${nm}-chat-container form button{cursor:pointer;color:#8f12fd;background-color:#f7f7f7;border:0;border-radius:4px;padding:20px 10px}${nm}-scrpt-chat-bottom-menu{padding-top:20px;list-style-type:none;text-align:center;padding-left:0;margin-left:0}${nm}-scrpt-chat-bottom-menu li{display:inline-block;padding-left:30px;padding-right:30px;cursor:pointer}${nm}-bottom-menu-icon{padding-bottom:5px;display:inline-block}${nm}-chat-content{display:block;width:100%;padding:10px;height:510px;overflow-y:scroll;position:relative;box-shadow:0 4px 2px -2px rgba(0,0,0,.1)}${nm}-fullscreen-button{border:0;background-color:#fff;border-radius:100%;padding-bottom:3px;float:right;margin-left:4px}${nm}-bubble-income,${nm}-bubble-outcome{border-top-left-radius:10px;border-top-right-radius:10px}${nm}-msg-box{display:inline-block;width:80%}${nm}-msg-box p{padding:7px}${nm}-income{float:left}${nm}-outcome{float:right}${nm}-bubble-outcome{background-color:gray;color:#fff;border-bottom-left-radius:10px}${nm}-bubble-income{background-color:#f7f7f7;color:#424242;border-bottom-right-radius:10px} + `; + } + + createChatContainerContent() { + const clrfx = document.createElement('span'); + clrfx.classList.add(`${nm}-clearfix`); + + this.chatContainer.innerHTML = ''; + const title = document.createElement('div'); + title.classList.add(`${nm}-scrpt-header`); + + const closeButton = document.createElement('button'); + closeButton.innerHTML = ` `; + closeButton.classList.add(`${nm}-close-button`); + closeButton.addEventListener("click", () => this.closeChat()); + + title.appendChild(closeButton); + + this.fullScreenButton = document.createElement('button'); + this.fullScreenButton.innerHTML = ``; + this.fullScreenButton.classList.add(`${nm}-fullscreen-button`); + this.fullScreenButton.addEventListener("click", () => this.fullscreenchat()); + title.appendChild(this.fullScreenButton); + + + const form = document.createElement('form'); + form.classList.add(`${nm}-content`); + + const text = document.createElement('input'); + text.requered = true; + text.id = `${nm}-text`; + text.type = "text"; + text.placeholder = this.inputText; + + this.btn = document.createElement('button'); + this.btn.innerHTML = ``; + + this.chatContent = document.createElement('div'); + this.chatContent.classList.add(`${nm}-chat-content`); + form.appendChild(this.chatContent); + form.appendChild(clrfx); + + form.appendChild(text); + form.appendChild(this.btn); + form.addEventListener('submit', this.submit.bind(this)); + + + const bottomMenuContainer = document.createElement('ul'); + bottomMenuContainer.classList.add(`${nm}-scrpt-chat-bottom-menu`); + + const bottomMenuContainerItems = [ + { + icon: ` + `, + text: 'Home', + click: function () { + alert(this.text); + } + }, + { + icon: ` + `, + text: 'Chat', + click: function () { + alert(this.text); + } + }, + { + icon: ` + `, + text: 'Help', + click: function () { + alert(this.text); + } + }, + ]; + + bottomMenuContainerItems.forEach(item => { + let li = document.createElement('li'); + let span = document.createElement('span'); + span.classList.add(`${nm}-bottom-menu-icon`); + span.innerHTML = item.icon; + li.appendChild(span); + let br = document.createElement('br'); + li.appendChild(br); + let text = document.createElement('span'); + text.innerHTML = item.text; + li.appendChild(text); + bottomMenuContainer.appendChild(li); + }); + + this.chatContainer.appendChild(title); + this.chatContainer.appendChild(form); + this.chatContainer.appendChild(clrfx); + this.chatContainer.appendChild(bottomMenuContainer); + } + + async submit(e) { + e.preventDefault(); + let id = this.generateUniqueId(); + let inpt = document.getElementById(`${nm}-text`); + let q = inpt.value; + if (q.trim() === '') { + return; + } + this.chatContent.innerHTML += this.chatStripe(false, q, ''); + inpt.disabled = true; + inpt.value = ''; + this.btn.disabled = true; + + let result = await this.makeRequest("POST", `${domain}/answer?name=${this.appName}`, { + question: q + }); + result = JSON.parse(result); + this.chatContent.innerHTML += this.chatStripe(true, ' ', id); + const messageDiv = document.getElementById(id); + + this.typeText(messageDiv, result.answer); + + } + + toggleOpen() { + this.open = !this.open; + if (this.open) { + this.openChat(); + } else { + this.closeChat(); + } + } + + fullscreenchat() { + if (this.chatContainer.style.width === chatWidth) { + this.chatContainer.style.width = `${window.innerWidth - 30}px`; + this.chatContainer.style.height = `${window.innerHeight - 125}px`; + } else { + this.chatContainer.style.width = chatWidth; + this.chatContainer.style.height = `auto`; + } + } + + closeChat() { + this.open = false; + // this.createChatContainerContent(); + this.chatIcon.classList.remove(`${nm}-hidden`); + this.closeIcon.classList.add(`${nm}-hidden`); + this.chatContainer.classList.add(`${nm}-hidden`); + } + + openChat() { + this.chatIcon.classList.add(`${nm}-hidden`); + this.closeIcon.classList.remove(`${nm}-hidden`); + this.chatContainer.classList.remove(`${nm}-hidden`); + } + + typeText(element, text) { + let index = 0; + let interval = setInterval(() => { + if (index < text.length) { + element.innerHTML += text.charAt(index); + index++; + this.chatContent.scrollTop = this.chatContent.scrollHeight; + } else { + clearInterval(interval); + let inpt = document.getElementById(`${nm}-text`); + inpt.disabled = false; + this.btn.disabled = false; + } + }, 20); + } + + uuidv4() { + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => + (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) + ); + } + + generateUniqueId() { + return this.uuidv4(); + } + + chatStripe(isAi, value, uniqueID) { + return (` +
${value}
+${e}
\n