123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732 |
- <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
- <link rel="stylesheet"
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
- <link rel="stylesheet"
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@48,400,1,0" />
- <!-- <link rel="stylesheet" href="{{ " /css/main.css" | prepend: site.baseurl }}"> -->
- <style>
- .user-icon {
- display: inline-block;
- position: relative;
- }
- .dropdown_header {
- display: inline-block;
- position: relative;
- z-index: 1000;
- background-color: #FFC907;
- }
- .dropdown-content_header {
- display: none;
- position: absolute;
- width: auto;
- overflow: auto;
- box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.4);
- /* background-color: rgba(255, 255, 255, 0); */
- background-color: white;
- font-family: Reforma2018, serif;
- font-size: 1em;
- }
- .dropdown_header.active .dropdown-content_header {
- display: block;
- }
- .dropdown-content_header a {
- display: block;
- color: #000000;
- padding: 5px;
- text-decoration: none;
- }
- .dropdown-content_header a:hover {
- color: #FFFFFF;
- background-color: #FFC907;
- }
- .dropdown_header:hover {
- /* Resetting styles for hover state */
- border: none;
- box-shadow: none;
- display: block;
- /* Or any other appropriate display value */
- grid-template-columns: initial;
- /* Or any other appropriate value */
- }
- /* Style for the modal */
- /* #navBar.modal {
- display: flex;
- flex-direction: column;
- align-items: center;
- } */
- #emailCode,
- #emailCodeVerify {
- flex-direction: row;
- align-items: center;
- margin-bottom: 10px;
- }
- #emailCode {
- display: block;
- }
- #emailCodeVerify {
- display: none;
- }
- .modal {
- display: none;
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- padding: 20px;
- background-color: white;
- border: 2px solid #ccc;
- z-index: 2000;
- width: 60%;
- height: 20%;
- text-align: center;
- font-family: Reforma2018, serif;
- font-size: 1em;
- }
- /* Additional styling for buttons */
- .btn_login_logout {
- position: relative;
- border-radius: 4px;
- background-color: transparent;
- border: 1px solid #29335C;
- font-family: Reforma2018, serif;
- margin: 10px;
- padding-left: 2px;
- padding-right: 2px;
- }
- .btn_login_logout.primary_login_logout {
- background-color: #FFC907;
- color: black;
- border: 1px solid #d3a500;
- }
- .btn_login_logout.is-large_login_logout {
- font-size: 1em;
- text-align: center;
- }
- .btn_login_logout:hover {
- cursor: pointer;
- background-color: #d3a500
- }
- @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- font-family: "Poppins", sans-serif;
- }
- .CRChatbot {
- background: #E3F2FD;
- }
- .chatbot-toggler {
- position: fixed;
- bottom: 30px;
- right: 35px;
- outline: none;
- border: none;
- height: 50px;
- width: 50px;
- display: flex;
- cursor: pointer;
- align-items: center;
- justify-content: center;
- border-radius: 50%;
- background: #FFC907;
- transition: all 0.2s ease;
- }
- .CRChatbot.show-chatbot .chatbot-toggler {
- transform: rotate(90deg);
- }
- .chatbot-toggler span {
- color: #fff;
- position: absolute;
- }
- .chatbot-toggler span:last-child,
- .CRChatbot.show-chatbot .chatbot-toggler span:first-child {
- opacity: 0;
- }
- .CRChatbot.show-chatbot .chatbot-toggler span:last-child {
- opacity: 1;
- }
- .chatbot {
- position: fixed;
- right: 35px;
- bottom: 90px;
- width: 420px;
- background: #fff;
- border-radius: 15px;
- overflow: hidden;
- opacity: 0;
- pointer-events: none;
- transform: scale(0.5);
- transform-origin: bottom right;
- box-shadow: 0 0 128px 0 rgba(0, 0, 0, 0.1),
- 0 32px 64px -48px rgba(0, 0, 0, 0.5);
- transition: all 0.1s ease;
- }
- .CRChatbot.show-chatbot .chatbot {
- opacity: 1;
- pointer-events: auto;
- transform: scale(1);
- }
- .chatbot header {
- padding: 16px 0;
- position: relative;
- text-align: center;
- color: #fff;
- background: #FFC907;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
- }
- .chatbot header span {
- position: absolute;
- right: 15px;
- top: 50%;
- display: none;
- cursor: pointer;
- transform: translateY(-50%);
- }
- header h2 {
- font-size: 1.4rem;
- }
- .chatbot .chatbox {
- overflow-y: auto;
- height: 510px;
- padding: 30px 20px 100px;
- }
- .chatbot :where(.chatbox, textarea)::-webkit-scrollbar {
- width: 6px;
- }
- .chatbot :where(.chatbox, textarea)::-webkit-scrollbar-track {
- background: #fff;
- border-radius: 25px;
- }
- .chatbot :where(.chatbox, textarea)::-webkit-scrollbar-thumb {
- background: #ccc;
- border-radius: 25px;
- }
- .chatbox .chat {
- display: flex;
- list-style: none;
- }
- .chatbox .outgoing {
- margin: 20px 0;
- justify-content: flex-end;
- }
- .chatbox .incoming span {
- width: 32px;
- height: 32px;
- color: #fff;
- cursor: default;
- text-align: center;
- line-height: 32px;
- align-self: flex-end;
- background:#FFC907;
- border-radius: 4px;
- margin: 0 10px 7px 0;
- }
- .chatbox .chat p {
- white-space: pre-wrap;
- padding: 12px 16px;
- border-radius: 10px 10px 0 10px;
- max-width: 75%;
- color: #fff;
- font-size: 0.95rem;
- background: #FFC907;
- }
- .chatbox .incoming p {
- border-radius: 10px 10px 10px 0;
- }
- .chatbox .chat p.error {
- color: #721c24;
- background: #f8d7da;
- }
- .chatbox .incoming p {
- color: #000;
- background: #f2f2f2;
- }
- .chatbot .chat-input {
- display: flex;
- gap: 5px;
- position: absolute;
- bottom: 0;
- width: 100%;
- background: #fff;
- padding: 3px 20px;
- border-top: 1px solid #ddd;
- }
- .chat-input textarea {
- height: 55px;
- width: 100%;
- border: none;
- outline: none;
- resize: none;
- max-height: 180px;
- padding: 15px 15px 15px 0;
- font-size: 0.95rem;
- }
- .chat-input span {
- align-self: flex-end;
- color:#FFC907;
- cursor: pointer;
- height: 55px;
- display: flex;
- align-items: center;
- visibility: hidden;
- font-size: 1.35rem;
- }
- .chat-input textarea:valid~span {
- visibility: visible;
- }
- @media (max-width: 490px) {
- .chatbot-toggler {
- right: 20px;
- bottom: 20px;
- }
- .chatbot {
- right: 0;
- bottom: 0;
- height: 100%;
- border-radius: 0;
- width: 100%;
- }
- .chatbot .chatbox {
- height: 90%;
- padding: 25px 15px 100px;
- }
- .chatbot .chat-input {
- padding: 5px 15px;
- }
- .chatbot header span {
- display: block;
- }
- }
- </style>
- <header class="site-header">
- <div class="wrapper">
- <a class="site-title" href="{{ site.baseurl }}/">{{ site.title }}</a>
- <img src="{% link assets/elements/icon_do.svg %}" alt="do-ocracy icon"
- style="height:40px; padding: 5px 0 0 20px;" />
- <nav class="site-nav">
- <a href="#" class="menu-icon">
- <svg viewBox="0 0 18 15">
- <path fill="#424242"
- d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.031C17.335,0,18,0.665,18,1.484L18,1.484z" />
- <path fill="#424242"
- d="M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0c0-0.82,0.665-1.484,1.484-1.484 h15.031C17.335,6.031,18,6.696,18,7.516L18,7.516z" />
- <path fill="#424242"
- d="M18,13.516C18,14.335,17.335,15,16.516,15H1.484C0.665,15,0,14.335,0,13.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.031C17.335,12.031,18,12.696,18,13.516L18,13.516z" />
- </svg>
- </a>
- <div class="trigger" style="display: inline-block;">
- {% for my_page in site.pages %}
- {% if my_page.title %}
- <a class="page-link{% if page.url == my_page.url %} page-link-active{% endif %}"
- href="{{ my_page.url | prepend: site.baseurl }}">{{ my_page.title }}</a>
- {% endif %}
- {% endfor %}
- <div class="user-icon" id="loginLogoutButton">
- <div id="login">
- <button class="btn_login_logout primary_login_logout is-large_login_logout" onclick="showLoginModal()"
- style="height: 42px; width: 100px; padding: 2px; text-align: center">
- <img src="{% link assets/tabler_icons/login.svg %}" alt="Login"> Login
- </button>
- </div>
- <div id="logout" class="dropdown_header">
- <button class="btn_login_logout primary_login_logout is-large_login_logout" onclick="toggleDropdown()"
- style="height: 40px; width: 40px; padding: 2px; text-align: center">
- <img src="{% link assets/tabler_icons/user.svg %}" alt="Login">
- </button>
- <div class="dropdown-content_header">
- <div id="emailText"
- style="padding: 10px; padding-top: 20px; margin-top: 1px; margin-bottom: 1px; height: 10 px">
- </div>
- <a href="#" style="padding: 10px; margin-top: 1px; margin-bottom: 1px; height: 10 px"
- @click="logout">Logout</a>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div id="navBar" class="modal"
- style="width: 40%; height: 15%; padding-top: 1%; flex-direction: column; justify-content: center; align-items: center;">
- <div id="emailCode" style="align-items: center; text-align: center;">
- <label for="emailInput">Enter your email:</label>
- <input type="email" id="emailInput" v-model="loginEmail" required>
- <div style="display: flex; flex-direction: row; justify-content: center; margin-top: 20px;">
- <button class="btn primary is-large" @click="sendOTP">Send Code</button>
- <span style="margin: 0 10px;"></span> <!-- Spacer -->
- <button class="btn primary is-large" @click="closeModal">Close</button>
- </div>
- </div>
- <div id="emailCodeVerify" style="text-align: center;">
- <label for="otpInput">Enter Code to Login:</label>
- <input type="text" id="otpInput" v-model="otpCode" required>
- <div style="display: flex; flex-direction: row; justify-content: center; margin-top: 20px;">
- <button class="btn primary is-large" @click="verifyOTP">Verify Code</button>
- <span style="margin: 0 10px;"></span> <!-- Spacer -->
- <button class="btn primary is-large" @click="sendOTPAagin">Send Code Again</button>
- <span style="margin: 0 10px;"></span> <!-- Spacer -->
- <button class="btn primary is-large" @click="closeModal">Close</button>
- </div>
- </div>
- </div>
- </nav>
- <!-- <!DOCTYPE html>
- <html lang="en" dir="ltr">
- <head>
- <meta charset="utf-8">
- <title>Chatbot in JavaScript | CodingNepal</title>
- <link rel="stylesheet" href="style.css">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <script src="script.js" defer></script>
- </head> -->
- <div class="CRChatbot">
- <button class="chatbot-toggler">
- <span class="material-symbols-rounded">search</span>
- <span class="material-symbols-outlined">close</span>
- </button>
- <div class="chatbot">
- <header>
- <h2>Search</h2>
- <span class="close-btn material-symbols-outlined">close</span>
- </header>
- <ul class="chatbox">
- <li class="chat incoming">
- <span class="material-symbols-outlined"><img src="/assets/elements/icon_do.svg" style="height:25px; padding: 3px 3px 3px 3px;"></img></span>
- <p>Search below for terms in the library of user-generated rules.
- <br>You can also browse the templates." <a href="https://communityrule.info/templates/" target="_blank">templates.</a>
- </p>
- </li>
- </ul>
- <div class="chat-input">
- <textarea placeholder="Enter keywords..." spellcheck="false" required></textarea>
- <span id="send-btn" class="material-symbols-rounded">send</span>
- </div>
- </div>
- </div>
- </header>
- <script>
- const chatbotToggler = document.querySelector(".chatbot-toggler");
- const closeBtn = document.querySelector(".close-btn");
- const chatbox = document.querySelector(".chatbox");
- const chatInput = document.querySelector(".chat-input textarea");
- const sendChatBtn = document.querySelector(".chat-input span");
- let userMessage = null; // Variable to store user's message
- const API_KEY = "PASTE-YOUR-API-KEY"; // Paste your API key here
- const inputInitHeight = chatInput.scrollHeight;
- const createChatLi = (message, className) => {
- // Create a chat <li> element with passed message and className
- const chatLi = document.createElement("li");
- chatLi.classList.add("chat", `${className}`);
- let chatContent = className === "outgoing" ? `<p></p>` : `<span class="material-symbols-outlined">smart_toy</span><p></p>`;
- chatLi.innerHTML = chatContent;
- chatLi.querySelector("p").textContent = message;
- return chatLi; // return chat <li> element
- }
- // const generateResponse = (chatElement) => {
- // const API_URL = "https://api.openai.com/v1/chat/completions";
- // const messageElement = chatElement.querySelector("p");
- // // Define the properties and message for the API request
- // const requestOptions = {
- // method: "POST",
- // headers: {
- // "Content-Type": "application/json",
- // "Authorization": `Bearer ${API_KEY}`
- // },
- // body: JSON.stringify({
- // model: "gpt-3.5-turbo",
- // messages: [{ role: "user", content: userMessage }],
- // })
- // }
- // // Send POST request to API, get response and set the reponse as paragraph text
- // fetch(API_URL, requestOptions).then(res => res.json()).then(data => {
- // messageElement.textContent = data.choices[0].message.content.trim();
- // }).catch(() => {
- // messageElement.classList.add("error");
- // messageElement.textContent = "Oops! Something went wrong. Please try again.";
- // }).finally(() => chatbox.scrollTo(0, chatbox.scrollHeight));
- // }
- const generateResponse = (chatElement) => {
- const apiUrl = new URL("http://127.0.0.1:5000/request");
- const params = { question: userMessage };
- apiUrl.search = new URLSearchParams(params).toString();
- const messageElement = chatElement.querySelector("p");
- // Define the properties and message for the API request
- const requestOptions = {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- },
- };
- // Send POST request to API, get response and set the reponse as paragraph text
- fetch(apiUrl, requestOptions)
- .then(res => res.json())
- .then(data => {
- // console.log(data)
- let responseMessage = 'Here are the top 3 most suitable community rules we found based on your description:<br>';
- data.forEach((item, index) => {
- const community = item.community.replace(/\n/g, '').trim();
- responseMessage += `${index + 1}. ${community}<br><a href="${item.link}" target="_blank">Learn more</a><br><br>`;
- });
- messageElement.innerHTML = responseMessage;
- }).catch((err) => {
- messageElement.classList.add("error");
- messageElement.textContent = "Oops! Something went wrong. Please try again.";
- }).finally(() => chatbox.scrollTo(0, chatbox.scrollHeight));
- }
- const handleChat = () => {
- userMessage = chatInput.value.trim(); // Get user entered message and remove extra whitespace
- if (!userMessage) return;
- // Clear the input textarea and set its height to default
- chatInput.value = "";
- chatInput.style.height = `${inputInitHeight}px`;
- // Append the user's message to the chatbox
- chatbox.appendChild(createChatLi(userMessage, "outgoing"));
- chatbox.scrollTo(0, chatbox.scrollHeight);
- setTimeout(() => {
- // Display "Thinking..." message while waiting for the response
- const incomingChatLi = createChatLi("Thinking...", "incoming");
- chatbox.appendChild(incomingChatLi);
- chatbox.scrollTo(0, chatbox.scrollHeight);
- generateResponse(incomingChatLi);
- }, 600);
- }
- chatInput.addEventListener("input", () => {
- // Adjust the height of the input textarea based on its content
- chatInput.style.height = `${inputInitHeight}px`;
- chatInput.style.height = `${chatInput.scrollHeight}px`;
- });
- chatInput.addEventListener("keydown", (e) => {
- // If Enter key is pressed without Shift key and the window
- // width is greater than 800px, handle the chat
- if (e.key === "Enter" && !e.shiftKey && window.innerWidth > 800) {
- e.preventDefault();
- handleChat();
- }
- });
- sendChatBtn.addEventListener("click", handleChat);
- closeBtn.addEventListener("click", () => document.querySelector(".CRChatbot").classList.remove("show-chatbot"));
- chatbotToggler.addEventListener("click", () => document.querySelector(".CRChatbot").classList.toggle("show-chatbot"));
- function toggleDropdown() {
- var dropdown = document.getElementById('logout');
- dropdown.classList.toggle('active');
- var myDiv = document.getElementById('emailText'); // Get the div element by ID
- myDiv.textContent = localStorage.getItem('userEmail');
- }
- function showLoginModal() {
- // Show the modal and overlay
- document.getElementById('navBar').style.display = 'block';
- document.getElementById('overlay').style.display = 'block';
- }
- function logout() {
- // Remove email from local storage
- localStorage.removeItem('userEmail');
- // Hide the dropdown and overlay
- document.getElementById('login').style.display = 'block';
- document.getElementById('logout').style.display = 'none';
- document.getElementById('emailCode').style.display = 'block';
- document.getElementById('emailCodeVerify').style.display = 'none';
- window.location.reload();
- }
- // function showLoginModal() {
- // document.getElementById('navBar').style.display = 'block';
- // // document.getElementById('overlay').style.display = 'block';
- // }
- function hideLoginModal() {
- document.getElementById('navBar').style.display = 'none';
- document.getElementById('overlay').style.display = 'none';
- }
- function isValidEmail(email) {
- // Regular expression for a basic email validation
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
- return emailRegex.test(email);
- }
- new Vue({
- el: '#loginLogoutButton',
- data: {
- email: localStorage.getItem('userEmail') || null,
- showDropdown: false,
- },
- mounted() {
- // Retrieve email from local storage on component mount
- this.email = localStorage.getItem('userEmail');
- if (this.email) {
- document.getElementById('login').style.display = 'none';
- document.getElementById('logout').style.display = 'block';
- } else {
- document.getElementById('login').style.display = 'block';
- document.getElementById('logout').style.display = 'none';
- }
- },
- });
- new Vue({
- el: '#navBar',
- data: {
- loginEmail: '',
- email: localStorage.getItem('userEmail'),
- otpCode: "",
- backendUrlOtp: "/api/send_otp",
- backendUrlValidateOtp: "/api/validate_otp"
- },
- methods: {
- sendOTPAagin() {
- document.getElementById('emailCode').style.display = 'block';
- document.getElementById('emailCodeVerify').style.display = 'none';
- },
- sendOTP() {
- const requestData = {
- email: this.loginEmail
- }
- if (isValidEmail(this.loginEmail)) {
- fetch(this.backendUrlOtp, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Access-Control-Allow-Methods': 'POST',
- 'Access-Control-Allow-Headers': 'Content-Type'
- // Add any other headers you may need, such as authorization headers
- },
- body: JSON.stringify(requestData),
- }).then(response => {
- if (!response.ok) {
- alert('Error while sending OTP');
- } else {
- alert(`Code sent to: ${this.loginEmail}`);
- document.getElementById('emailCode').style.display = 'none';
- document.getElementById('emailCodeVerify').style.display = 'block';
- }
- })
- } else {
- alert(`Please enter valid email address`);
- }
- },
- verifyOTP() {
- const requestData = {
- email: this.loginEmail,
- otp: this.otpCode
- }
- fetch(this.backendUrlValidateOtp, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Access-Control-Allow-Methods': 'POST',
- 'Access-Control-Allow-Headers': 'Content-Type'
- // Add any other headers you may need, such as authorization headers
- },
- body: JSON.stringify(requestData),
- }).then(response => {
- if (response.status == 500) {
- alert('Error while validating code');
- } else if (response.status == 200) {
- alert('Logged in successfully');
- localStorage.setItem('userEmail', this.loginEmail)
- document.getElementById('login').style.display = 'none';
- document.getElementById('logout').style.display = 'block';
- document.getElementById('logout').classList.remove('active');
- this.closeModal();
- } else {
- alert('Invalid code, please enter valid code');
- }
- })
- },
- closeModal() {
- document.getElementById('navBar').style.display = 'none';
- },
- },
- });
-
- </script>
|