diff --git a/assets/fonts/Roboto/Roboto-Regular.ttf b/assets/fonts/Roboto/Roboto-Regular.ttf new file mode 100644 index 0000000..ddf4bfa Binary files /dev/null and b/assets/fonts/Roboto/Roboto-Regular.ttf differ diff --git a/index.html b/index.html index d64c7a4..db7273e 100644 --- a/index.html +++ b/index.html @@ -1,10 +1,136 @@ - - - - Document - - - - \ No newline at end of file + + + + Contact Us + + + +
+

Contact us

+
+
+
+
+ Name + + +
+
+ Last Name + + +
+ +
+ Tel + + +
+
+ Purpose of contact + + +
+
+ Contact me via + + + +
+ + + +
+
+ Message + + + +
+ + +
+
+ + +

Terms and policies

+

+ 1. ACCEPTANCE THE USE OF LOREM IPSUM TERMS AND CONDITIONS Your access to + and use of Lorem Ipsum (the app) is subject exclusively to these Terms + and Conditions. You will not use the app for any purpose that is + unlawful or prohibited by these Terms and Conditions. By using the app + you are fully accepting the terms, conditions and disclaimers contained + in this notice. If you do not accept these Terms and Conditions you must + immediately stop using the app.

+ 2. CREDIT CARD DETAILS All Lorem Ipsum purchases are managed by the + individual App Stores (Apple, Google Windows) and Lorem Ipsum will never + store your credit card information or make it available to any third + parties. Any purchasing information provided will be provided directly + from you to the respective App Store and you will be subject to their + credit card policies.

+ 3. LEGAL ADVICE The contents of Lorem Ipsum app do not constitute advice + and should not be relied upon in making or refraining from making, any + decision. All material contained on Lorem Ipsum is provided without any + or warranty of any kind. You use the material on Lorem Ipsum at your own + discretion

+ 4. CHANGE OF USE Lorem Ipsum reserves the right to:
+ 4.1 change or remove (temporarily or permanently) the app or any part of + it without notice and you confirm that Lorem Ipsum shall not be liable + to you for any such change or removal and.
+ 4.2 change these Terms and Conditions at any time, and your continued + use of the app following any changes shall be deemed to be your + acceptance of such change. +

+ + +
+ + + diff --git a/js/script.js b/js/script.js new file mode 100644 index 0000000..6460a60 --- /dev/null +++ b/js/script.js @@ -0,0 +1,184 @@ +const form = document.querySelector("form"); +const checkboxMessage = document.querySelector("input[name='checkboxMessage']"); +const checkboxTerms = document.querySelector("input[name='checkboxTerms']"); +const radioButtonsContactVia = Array.from( + document.querySelectorAll("input[name='Contact via']") +); +const dropdown = document.querySelector("select"); +const modal = document.querySelector(".modal"); +const modalText = document.querySelector(".modalText"); +const modalCloseButton = document.querySelector(".closeModalButton"); +const modalContinueButton = document.querySelector(".continueModalButton"); + +function initializeInputs() { + // refresh all inputs on reload (Firefox) and add event listeners + const textInputs = document.querySelectorAll( + 'select,input:not([type="checkbox"],[type="radio"],.notRequired)' + ); + const buttons = document.querySelectorAll( + 'input:is([type="checkbox"],[type="radio"]):not(.notRequired)' + ); + + textInputs.forEach((textInput) => { + textInput.value = ""; + textInput.addEventListener("input", (e) => validateInput(e.target)); + }); + dropdown.addEventListener("change", () => + dropdown.classList.remove("invalid") + ); + buttons.forEach((button) => { + button.checked = false; + button.addEventListener("click", (e) => validateInput(e.target)); + }); + checkboxMessage.checked = false; +} + +window.addEventListener("load", () => initializeInputs()); + +function handleRadioButtonTelEmailClick(clickedRadioButtonTelEmail) { + const radioButtonsEmailSpecification = Array.from( + document.querySelectorAll("input[name='Email specification']") + ); + + radioButtonsEmailSpecification.forEach((radioButtonEmailSpecification) => { + if (clickedRadioButtonTelEmail.id === "email") { + radioButtonEmailSpecification.parentElement.classList.remove("hidden"); + } else { + radioButtonEmailSpecification.parentElement.classList.add("hidden"); + radioButtonEmailSpecification.parentElement.classList.remove("invalid"); + radioButtonEmailSpecification.checked = false; + } + }); +} + +radioButtonsContactVia.forEach((radioButtonContactVia) => { + radioButtonContactVia.addEventListener("click", () => + handleRadioButtonTelEmailClick(radioButtonContactVia) + ); +}); + +checkboxMessage.addEventListener("click", () => { + const messageTextInput = document.querySelector("input[name='MessageText']"); + if (messageTextInput.classList.contains("hidden")) { + messageTextInput.classList.remove("hidden"); + } else { + messageTextInput.value = ""; + messageTextInput.classList.add("hidden"); + messageTextInput.classList.remove("invalid"); + } +}); + +function validateButton(buttonName) { + const buttons = Array.from( + document.querySelectorAll(`input[name='${buttonName}']`) + ); + let isAnyButtonClicked = false; + + buttons.forEach((button) => { + button.parentElement.classList.remove("invalid"); + if (button.checked) { + isAnyButtonClicked = true; + button.classList.remove("notRequired"); + } else { + button.classList.add("notRequired"); + } + }); + if (!isAnyButtonClicked) { + //none of the buttons are clicked + buttons.forEach((button) => { + button.parentElement.classList.add("invalid"); + button.classList.remove("notRequired"); + }); + } + + return isAnyButtonClicked; +} + +function validateInput(input) { + let isInputValid = false; + + switch (input.type) { + case "text": + isInputValid = + input.value.trim().length > 0 && input.value.trim().length <= 50; + break; + case "email": + const EmailRegEx = /^[\w-.]+@([\w-]+\.)+[\w-]{2,}$/; + isInputValid = EmailRegEx.test(input.value); + break; + case "tel": + const TelRegEx = /^\d{9,10}$/; + input.value = input.value.replace(/\D/g, ""); + isInputValid = TelRegEx.test(input.value); + break; + case "select-one": + isInputValid = input.value !== ""; + break; + case "radio": + isInputValid = validateButton(input.name); + break; + default: + return true; + } + + if (isInputValid) input.classList.remove("invalid"); + else input.classList.add("invalid"); + return isInputValid; +} + +function validateForm(formEvent) { + formEvent.preventDefault(); + + const inputs = Array.from( + document.querySelectorAll( + "select,input:not(.hidden,.hidden *,.notRequired,[type='checkbox'])" + ) + ); + let isFormValid = true; + + inputs.forEach((input) => { + if (!validateInput(input)) isFormValid = false; + }); + + if (!checkboxTerms.checked) { + isFormValid = false; + checkboxTerms.parentElement.classList.add("invalid"); + } + + if (!isFormValid) return; + + const inputsText = inputs + .filter((input) => input.value !== "on") + .map((filteredInput) => `${filteredInput.name}: ${filteredInput.value}`) + .join("\n"); + + alert(inputsText); +} + +form.addEventListener("submit", (e) => validateForm(e)); + +checkboxTerms.addEventListener("click", (e) => { + if (!modalContinueButton.disabled) modalContinueButton.disabled = true; + + if (checkboxTerms.checked) { + e.preventDefault(); + modal.showModal(); + } else checkboxTerms.checked = false; +}); + +modalCloseButton.addEventListener("click", () => { + modalText.scrollTop = 0; + modal.close(); +}); +modalContinueButton.addEventListener("click", () => { + checkboxTerms.checked = true; + checkboxTerms.parentElement.classList.remove("invalid"); + modalText.scrollTop = 0; + modal.close(); +}); + +modalText.addEventListener("scroll", (e) => { + const { scrollHeight, scrollTop, clientHeight } = e.target; + if (Math.abs(scrollHeight - clientHeight - scrollTop) < 1) + modalContinueButton.disabled = false; +}); diff --git a/styles/styles.css b/styles/styles.css new file mode 100644 index 0000000..6dc3ffd --- /dev/null +++ b/styles/styles.css @@ -0,0 +1,171 @@ +@font-face { + font-family: "Roboto"; + src: url("../assets/fonts/Roboto/Roboto-Regular.ttf"); +} +body { + display: grid; + place-items: center; +} + +* { + font-family: "Roboto", sans-serif; +} + +h1 { + color: rgb(57, 144, 173); +} + +.form { + border: 2px solid rgb(57, 144, 173); + padding: 15px; + display: grid; + grid-template-columns: 200px 200px; + gap: 15px; + border-radius: 7px; +} +.form .inputContainer { + position: relative; + text-align: center; + border-radius: 5px; +} +.form .inputContainer.message { + grid-column: 1/-1; +} +.form .inputContainer legend { + color: rgb(57, 144, 173); +} +.form .inputContainer input, +.form .inputContainer select { + outline: none; + border: none; + background: none; + border-bottom: 2px solid rgb(57, 144, 173); + border-radius: 0px; + color: black; +} +.form .inputContainer input.invalid, +.form .inputContainer select.invalid { + position: relative; + border: 2px solid red; +} +.form input[type=text] { + width: 80%; +} +.form input:is([type=radio], [type=checkbox]) { + accent-color: rgb(57, 144, 173); +} +.form input:-webkit-autofill, .form input:-webkit-autofill:hover, .form input:-webkit-autofill:focus, .form input:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 30px white inset !important; +} +.form label { + width: fit-content; + display: inline-flex; + align-items: center; + white-space: nowrap; +} +.form label.invalid { + background-color: rgb(250, 208, 209); +} +.form #emailSpecificationLabel1 { + margin-bottom: 3px; +} +.form .hidden, +.form .invalidText { + display: none; +} +.form .invalid + .invalidText, +.form .invalid .invalidText { + display: inline-block; + color: red; + white-space: nowrap; + font-size: 0.8em; +} +.form .termsLabel { + position: relative; + transform: translateX(20%); +} +.form .termsLabel .invalidText { + position: absolute; + top: 100%; + left: -15%; + font-size: 0.8em; +} +.form .registerButton { + color: white; + background-color: rgb(57, 144, 173); + border: none; + border-radius: 5px; + transition: 0.2s; +} +.form .registerButton:hover { + transform: scale(1.05); +} + +.modal { + position: absolute; + left: 50%; + right: 50%; + z-index: 10; + margin-top: 10px; + width: 300px; + border: none; + border-radius: 1rem; + transform: translate(-50%, 50%); +} +.modal .modalTitle { + text-align: center; + margin-block: 5px; +} +.modal .modalText { + display: inline-block; + height: 100px; + line-height: 20px; + border-top: 1px solid grey; + border-bottom: 1px solid grey; + font-size: 0.9em; + overflow: auto; +} +.modal button { + padding: 10px; + text-align: center; + border-radius: 5px; + border: none; + color: white; + margin-inline-end: 6px; + cursor: pointer; +} +.modal .closeModalButton { + background-color: rgb(148, 148, 148); +} +.modal .continueModalButton { + background-color: rgb(57, 144, 173); +} +.modal .continueModalButton:disabled { + opacity: 0.5; + cursor: not-allowed; +} +.modal::backdrop { + background-color: rgba(0, 0, 0, 0.3); + backdrop-filter: blur(2px); +} + +@media (max-width: 500px) { + *:not(h1) { + font-size: 0.95em; + } + h1 { + margin-block: 0; + font-size: 1.5em; + } + .form { + grid-template-columns: 170px 170px; + gap: 5px; + } + .form .inputContainer { + grid-column: 1/-1; + } + .form .inputContainer input, + .form .inputContainer select { + width: 80%; + } +}/*# sourceMappingURL=styles.css.map */ \ No newline at end of file diff --git a/styles/styles.css.map b/styles/styles.css.map new file mode 100644 index 0000000..5891557 --- /dev/null +++ b/styles/styles.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["styles.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACE;EACA;;AAMJ;EACE;;AAGF;EACE;;AAGF;EAIE;;AAIJ;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAIJ;EACE;;AAGF;AAAA;EAEE;;AAGF;AAAA;EAEE;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAIJ;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAKN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAEA;EACE;EACA;;AAIJ;EACE;EACA;;;AAIJ;EACE;IACE;;EAEF;IACE;IACA;;EAEF;IACE;IACA;;EAEA;IACE;;EAEA;AAAA;IAEE","file":"styles.css"} \ No newline at end of file diff --git a/styles/styles.scss b/styles/styles.scss new file mode 100644 index 0000000..fd16572 --- /dev/null +++ b/styles/styles.scss @@ -0,0 +1,202 @@ +@font-face { + font-family: "Roboto"; + src: url("../assets/fonts/Roboto/Roboto-Regular.ttf"); +} + +body { + display: grid; + place-items: center; +} + +* { + font-family: "Roboto", sans-serif; +} + +h1 { + color: rgb(57, 144, 173); +} + +.form { + border: 2px solid rgb(57, 144, 173); + padding: 15px; + display: grid; + grid-template-columns: 200px 200px; + gap: 15px; + border-radius: 7px; + + .inputContainer { + position: relative; + text-align: center; + border-radius: 5px; + + &.message { + grid-column: 1/-1; + } + + legend { + color: rgb(57, 144, 173); + } + + input, + select { + outline: none; + border: none; + background: none; + border-bottom: 2px solid rgb(57, 144, 173); + border-radius: 0px; + color: black; + + &.invalid { + position: relative; + border: 2px solid red; + } + } + } + + input { + &[type="text"] { + width: 80%; + } + + &:is([type="radio"], [type="checkbox"]) { + accent-color: rgb(57, 144, 173); + } + + &:-webkit-autofill, /*remove autofill style*/ + &:-webkit-autofill:hover, + &:-webkit-autofill:focus, + &:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 30px white inset !important; + } + } + + label { + width: fit-content; + display: inline-flex; + align-items: center; + white-space: nowrap; + + &.invalid { + background-color: rgb(250, 208, 209); + } + } + + #emailSpecificationLabel1 { + margin-bottom: 3px; + } + + .hidden, + .invalidText { + display: none; + } + + .invalid + .invalidText, + .invalid .invalidText { + display: inline-block; + color: red; + white-space: nowrap; + font-size: 0.8em; + } + + .termsLabel { + position: relative; + transform: translateX(20%); + + .invalidText { + position: absolute; + top: 100%; + left: -15%; + font-size: 0.8em; + } + } + + .registerButton { + color: white; + background-color: rgb(57, 144, 173); + border: none; + border-radius: 5px; + transition: 0.2s; + + &:hover { + transform: scale(1.05); + } + } +} + +.modal { + position: absolute; + left: 50%; + right: 50%; + z-index: 10; + margin-top: 10px; + width: 300px; + border: none; + border-radius: 1rem; + transform: translate(-50%, 50%); + + .modalTitle { + text-align: center; + margin-block: 5px; + } + + .modalText { + display: inline-block; + height: 100px; + line-height: 20px; + border-top: 1px solid grey; + border-bottom: 1px solid grey; + font-size: 0.9em; + overflow: auto; + } + + button { + padding: 10px; + text-align: center; + border-radius: 5px; + border: none; + color: white; + margin-inline-end: 6px; + cursor: pointer; + } + + .closeModalButton { + background-color: rgb(148, 148, 148); + } + + .continueModalButton { + background-color: rgb(57, 144, 173); + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } + } + + &::backdrop { + background-color: rgba(0, 0, 0, 0.3); + backdrop-filter: blur(2px); + } +} + +@media (max-width: 500px) { + *:not(h1) { + font-size: 0.95em; + } + h1 { + margin-block: 0; + font-size: 1.5em; + } + .form { + grid-template-columns: 170px 170px; + gap: 5px; + + .inputContainer { + grid-column: 1/-1; + + input, + select { + width: 80%; + } + } + } +}