diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..25e94f88 Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md index 60f55e53..0742d21a 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ # Project Name -Replace this readme with your own information about your project. - -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +The project was to create a chatbot that interacts with the user using DOM, functions and event listeners ## The problem -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +I tackled the project by creating a scenario for how the conversation would flow and then tried to set up functions for each step of the conversation. + +If there had been more time I would have tried to get the chatbot to fetch real weather data. The chatbot does not show a message for invalid input when typing in something else than the suggested occasions, which I would add if I had more time for the project, alternatively using buttons for the options as well. + + ## View it live -Have you deployed your project somewhere? Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +https://rococo-stroopwafel-4da0eb.netlify.app/ \ No newline at end of file diff --git a/code/assets/bot.png b/bot.png similarity index 100% rename from code/assets/bot.png rename to bot.png diff --git a/code/.DS_Store b/code/.DS_Store new file mode 100644 index 00000000..3ab66bc8 Binary files /dev/null and b/code/.DS_Store differ diff --git a/code/assets/.DS_Store b/code/assets/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/code/assets/.DS_Store differ diff --git a/code/index.html b/code/index.html deleted file mode 100644 index 316eb187..00000000 --- a/code/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - Chatbot - - - -

Welcome to my chatbot!

-
-
-
-
- - - -
-
-
- - - - - diff --git a/code/script.js b/code/script.js deleted file mode 100644 index 125d6904..00000000 --- a/code/script.js +++ /dev/null @@ -1,53 +0,0 @@ -// DOM selectors (variables that point to selected DOM elements) goes here 👇 -const chat = document.getElementById('chat') - -// Functions goes here 👇 - -// A function that will add a chat bubble in the correct place based on who the sender is -const showMessage = (message, sender) => { - // The if statement checks if the sender is the user and if that's the case it inserts - // an HTML section inside the chat with the posted message from the user - if (sender === 'user') { - chat.innerHTML += ` -
-
-

${message}

-
- User -
- ` - // The else if statement checks if the sender is the bot and if that's the case it inserts - // an HTML section inside the chat with the posted message from the bot - } else if (sender === 'bot') { - chat.innerHTML += ` -
- Bot -
-

${message}

-
-
- ` - } - - // This little thing makes the chat scroll to the last message when there are too many to - // be shown in the chat box - chat.scrollTop = chat.scrollHeight -} - -// A function to start the conversation -const greetUser = () => { - // Here we call the function showMessage, that we declared earlier with the argument: - // "Hello there, what's your name?" for message, and the argument "bot" for sender - showMessage("Hello there, what's your name?", 'bot') - // Just to check it out, change 'bot' to 'user' here 👆 and see what happens -} - -// Eventlisteners goes here 👇 - -// Here we invoke the first function to get the chatbot to ask the first question when -// the website is loaded. Normally we invoke functions like this: greeting() -// To add a little delay to it, we can wrap it in a setTimeout (a built in JavaScript function): -// and pass along two arguments: -// 1.) the function we want to delay, and 2.) the delay in milliseconds -// This means the greeting function will be called one second after the website is loaded. -setTimeout(greetUser, 1000) diff --git a/code/style.css b/code/style.css deleted file mode 100644 index a275402f..00000000 --- a/code/style.css +++ /dev/null @@ -1,150 +0,0 @@ -* { - box-sizing: border-box; -} - -body { - margin: 0; - padding: 0; - font-family: 'Montserrat', sans-serif; - background: #0026ff; -} - -h1 { - font-weight: bold; - font-size: 28px; - line-height: 34px; - color: #fff; - text-align: center; -} - -h2 { - font-weight: bold; - font-size: 24px; - line-height: 34px; - color: #fff; - text-align: center; - margin-bottom: 36px; -} - -p { - font-size: 18px; - font-weight: 600; - line-height: 28px; - margin: 0; -} - -input { - box-sizing: border-box; - border: none; - border-radius: 4px 0 0 4px; - background: #e5e9ff; - color: #0026ff; - padding: 16px; - font-size: 16px; - font-family: 'Montserrat'; - font-weight: 600; - line-height: 26px; - flex: 1; - width: 100%; -} - -main { - margin: 0 auto; - width: 100%; - max-width: 700px; - height: 600px; - border-radius: 30px; - background: #fff; - padding: 20px 24px; - padding-top: 0; - box-sizing: border-box; - display: flex; - flex-direction: column; -} - -.chat { - flex: 1; - display: flex; - justify-content: flex-start; - overflow: scroll; - flex-direction: column; - padding-bottom: 16px; -} - -.bot-msg { - display: flex; - margin: 16px 8px 0 0; - flex-shrink: 0; -} - -.user-msg { - display: flex; - justify-content: flex-end; - margin: 16px 0 0 8px; - flex-shrink: 0; -} - -.bot-msg img, -.user-msg img { - width: 60px; - height: 60px; -} - -.bubble { - background: #e5e9ff; - font-weight: 600; - font-size: 16px; - line-height: 26px; - padding: 16px 24px; - color: #0026ff; - max-width: 40%; -} - -.bot-bubble { - border-radius: 0px 26px 26px 26px; - margin-left: 8px; -} - -.user-bubble { - border-radius: 26px 0 26px 26px; - margin-right: 8px; -} - -.input-wrapper { - display: flex; - justify-content: center; -} - -.input-wrapper form { - width: 100%; - display: flex; - align-items: center; -} - -label { - font-size: 16px; - font-family: 'Montserrat'; - font-weight: 500; - color: #0026ff; - margin-right: 20px; -} - -button { - background-color: #0026ff; - color: white; - border: none; - border-radius: 4px; - padding: 16px 20px; - margin-right: 4px; - font-size: 16px; - line-height: 26px; - font-family: 'Montserrat'; - font-weight: 500; - cursor: pointer; - transition: all 0.3s ease; -} - -button:hover { - opacity: 0.9; - transition: all 0.2s ease; -} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..06443f03 --- /dev/null +++ b/index.html @@ -0,0 +1,32 @@ + + + + + + + + + Weather Wardrobe + + + +

Welcome to Weather Wardrobe!🌤️

+
+
+
+
+ + + +
+
+
+ + + + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 00000000..66eba000 --- /dev/null +++ b/script.js @@ -0,0 +1,201 @@ +// DOM selectors (variables that point to selected DOM elements) goes here 👇 +const chat = document.getElementById('chat') +const locationForm = document.getElementById('location-form') +const locationInput = document.getElementById('location-input') + + +// Functions goes here 👇 + +// A function that will add a chat bubble in the correct place based on who the sender is +const showMessage = (message, sender) => { + // The if statement checks if the sender is the user and if that's the case it inserts + // an HTML section inside the chat with the posted message from the user + if (sender === 'user') { + chat.innerHTML += ` +
+
+

${message}

+
+ User +
+ ` + // The else if statement checks if the sender is the bot and if that's the case it inserts + // an HTML section inside the chat with the posted message from the bot + } else if (sender === 'bot') { + // add a console.log here to see when it's being logged and not + console.log("Message is:", message); + console.log("Sender is:", sender); + chat.innerHTML += ` +
+ Bot +
+

${message}

+
+
+ ` + } + + // This little thing makes the chat scroll to the last message when there are too many to + // be shown in the chat box + chat.scrollTop = chat.scrollHeight + + // Clear the input field after submission + locationInput.value = '' +} + +// A function to start the conversation +const greetUser = () => { + showMessage("Hello, I can help you choose the perfect outfit based on the weather. What's your location?📍", 'bot') +} + +// A function for the location input +const handleLocationInput = (event) => { + event.preventDefault() // Prevent from refreshing the page + const userLocation = locationInput.value + + if (userLocation) { + showMessage(userLocation, 'user') + + + // Remove the event listener for location input after being hanlded + locationForm.removeEventListener('submit', handleLocationInput); + + // Checking weather... + setTimeout(() => { + showMessage(`Checking the weather for ${userLocation}...`, 'bot') + + setTimeout(() => { + const weather = "sunny☀️ and between 18-20 degrees" + showMessage(`It looks like it's going to be ${weather} today in ${userLocation}.`, 'bot') + setTimeout(showClothingOptions, 1000) + }, 2000) + }, 1000) + } +} + +// Function to create buttons for choosing casual or formal clothing +const showClothingOptions = () => { + locationForm.removeEventListener('submit', handleInvalidInput); + + chat.innerHTML += ` +
+ Bot +
+

Would you prefer casual or formal clothing?

+ + +
+
+ ` + + // Function to handle clothing choice + const handleClothingChoice = (event) => { + const choice = event.target.getAttribute('data-choice'); + + if (choice) { + showMessage(`I prefer ${choice} clothing.`, 'user'); + + // Remove event listeners + const buttons = document.querySelectorAll('.clothing-choice'); + buttons.forEach(button => { + button.removeEventListener('click', handleClothingChoice); + }); + + // Remove event listener for invalid input after a valid choice + locationForm.removeEventListener('submit', handleInvalidInput); + + // Ask about the occasion + setTimeout(() => { + askForOccasion(choice); + }, 1000); + } + } + + // Function to ask about the occasion + const askForOccasion = (clothingChoice) => { + showMessage("Are you dressing for a specific occasion or activity (e.g., work, party, exercise)?", 'bot'); + + const occasionInputHandler = (event) => handleOccasionInput(event, clothingChoice, occasionInputHandler); + locationForm.addEventListener('submit', occasionInputHandler); + } + + // Eevent listeners to the buttons to handle the user's choice + const buttons = document.querySelectorAll('.clothing-choice'); + buttons.forEach(button => { + button.addEventListener('click', handleClothingChoice); + }); + + // Event listener to handle invalid input + locationForm.addEventListener('submit', handleInvalidInput); + +} + +// Function to handle invalid input (user typing text instead of clicking buttons) +const handleInvalidInput = (event) => { + event.preventDefault(); + + const userInput = locationInput.value; + + if (userInput) { + showMessage(userInput, 'user'); + showMessage("That's not a valid answer. Please refresh the chat and try again.", 'bot'); + + } +}; + +// Function to handle the occasion input +const handleOccasionInput = (event, clothingChoice, occasionInputHandler) => { + event.preventDefault(); + + const occasion = locationInput.value; + if (occasion) { + showMessage(occasion, 'user'); + locationInput.value = ''; + + // Remove the event listener to prevent duplicates + locationForm.removeEventListener('submit', occasionInputHandler); + + setTimeout(() => { + OutfitSuggestion(clothingChoice, occasion); + }, 1000); + } +} + +// Function for outfit suggestion +const OutfitSuggestion = (clothingChoice, occasion) => { + let suggestion = ''; + + if (clothingChoice === 'casual') { + if (occasion.toLowerCase().includes('work')) { + suggestion = "A casual shirt and chinos might be perfect for work. 👔"; + } else if (occasion.toLowerCase().includes('party')) { + suggestion = "How about jeans and a stylish t-shirt for the party? 🎉"; + } else if (occasion.toLowerCase().includes('exercise')) { + suggestion = "Athletic wear would be great for exercising! 🏃"; + } else { + suggestion = "A t-shirt and jeans would be great! 👕👖"; + } + } else if (clothingChoice === 'formal') { + if (occasion.toLowerCase().includes('work')) { + suggestion = "A blazer with dress pants would suit you well for work. 💼"; + } else if (occasion.toLowerCase().includes('party')) { + suggestion = "A cocktail dress or a sharp suit would be ideal for the party. 🥂"; + } else if (occasion.toLowerCase().includes('exercise')) { + suggestion = "For exercise, comfort is key! Maybe opt for formal sportswear. 😉"; + } else { + suggestion = "A suit and tie might be a great option! 👔"; + } + } + + showMessage(suggestion, 'bot'); + + // End the conversation + setTimeout(() => { + showMessage("Let me know if you need anything else!", 'bot'); + }, 2000); +} + +setTimeout(greetUser, 1000) + +// Listen for the form submit event to capture user's location input +locationForm.addEventListener('submit', handleLocationInput) diff --git a/style.css b/style.css new file mode 100644 index 00000000..dc1ac8a9 --- /dev/null +++ b/style.css @@ -0,0 +1,245 @@ +* { + box-sizing: border-box; +} + +body { + margin: 0; + padding: 0; + font-family: 'Open Sans', sans-serif; + background: linear-gradient(to bottom right, #f0f4f8, #d9e2ec); +} + +h1, +h2 { + font-weight: 700; + color: #102a43; + text-align: center; +} + +h1 { + font-size: 32px; + margin-top: 20px; +} + +h2 { + font-size: 24px; + margin-bottom: 36px; +} + +p { + font-size: 18px; + font-weight: 600; + line-height: 28px; + margin: 0; + color: #334e68; +} + +input { + border: 1px solid #bcccdc; + border-radius: 8px 0 0 8px; + background: #fff; + color: #102a43; + padding: 16px; + font-size: 16px; + flex: 1; + width: 100%; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); +} + +main { + margin: 0 auto; + width: 100%; + max-width: 700px; + height: 600px; + border-radius: 16px; + background: #fff; + padding: 20px 24px; + box-sizing: border-box; + display: flex; + flex-direction: column; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} + +.chat { + flex: 1; + display: flex; + flex-direction: column; + overflow-y: auto; + padding-bottom: 16px; +} + +.bot-msg, +.user-msg { + display: flex; + margin-top: 16px; +} + +.bot-msg { + align-items: flex-start; +} + +.user-msg { + align-items: flex-end; + justify-content: flex-end; +} + +.bot-msg img, +.user-msg img { + width: 50px; + height: 50px; + border-radius: 50%; +} + +.bubble { + background: #f0f4f8; + font-weight: 500; + font-size: 16px; + line-height: 24px; + padding: 12px 20px; + color: #102a43; + max-width: 60%; +} + +.bot-bubble { + border-radius: 12px 12px 12px 0; + margin-left: 12px; +} + +.user-bubble { + background: #d9e2ec; + border-radius: 12px 12px 0 12px; + margin-right: 12px; +} + +.input-wrapper { + display: flex; + justify-content: center; + margin-top: 16px; +} + +.input-wrapper form { + width: 100%; + display: flex; + align-items: center; +} + +label { + font-size: 16px; + font-weight: 500; + color: #102a43; + margin-right: 16px; +} + +button { + background-color: #3e7cb1; + color: white; + border: none; + border-radius: 0 8px 8px 0; + padding: 16px 24px; + font-size: 16px; + font-weight: 600; + cursor: pointer; + transition: background-color 0.3s ease; +} + +button:hover { + background-color: #2a6f97; +} + +button:focus, +input:focus { + outline: none; + border-color: #3e7cb1; +} + +/* Media Queries for Responsiveness */ +@media (max-width: 768px) { + h1 { + font-size: 1.75em; + } + + h2 { + font-size: 1.25em; + } + + .bubble { + font-size: 0.95em; + padding: 0.65em 0.9em; + } + + input, + button { + padding: 0.65em; + font-size: 0.95em; + } + + .bot-msg img, + .user-msg img { + width: 40px; + height: 40px; + } +} + +@media (max-width: 480px) { + main { + width: 95%; + margin: 0.5em auto; + padding: 1em; + } + + h1 { + font-size: 1.5em; + } + + h2 { + font-size: 1.1em; + } + + .bubble { + font-size: 0.9em; + padding: 0.5em 0.8em; + } + + input, + button { + padding: 0.5em; + font-size: 0.9em; + } + + .bot-msg img, + .user-msg img { + width: 35px; + height: 35px; + } +} + +@media (min-width: 1200px) { + main { + max-width: 1200px; + } + + h1 { + font-size: 2.5em; + } + + h2 { + font-size: 2em; + } + + .bubble { + font-size: 1.1em; + padding: 1em 1.5em; + } + + input, + button { + padding: 1em; + font-size: 1.1em; + } + + .bot-msg img, + .user-msg img { + width: 60px; + height: 60px; + } +} \ No newline at end of file diff --git a/code/assets/user.png b/user.png similarity index 100% rename from code/assets/user.png rename to user.png