diff --git a/README.md b/README.md index 57e6d16..42e3fcd 100644 --- a/README.md +++ b/README.md @@ -1,9 +1 @@ -# Web Accessibility Project - -A basic web server template focused on web accessibility practices. - -### Installation - -1. Fork this repository by clicking the "Fork" button at the top right of the GitHub repository page. - -2. Clone your forked repository +Netlify link: https://js-project-accessibility.netlify.app/ \ No newline at end of file diff --git a/about.html b/about.html index 5adbad6..e517bd7 100644 --- a/about.html +++ b/about.html @@ -1,10 +1,164 @@ - - - - - About - - - - + + + + + + Web Accessebility Quiz + + + + + + + + + +
+
+
+

About Us

+

+ We are a team dedicated to getting this app done. Our mission is to learn to create a more inclusive world. + We believe that everyone deserves equal opportunities, and we strive to learn how to make that a reality + through + our work. +

+ +
+ + +
+
+ + + + + + + + \ No newline at end of file diff --git a/assets/celebrate.jpg b/assets/celebrate.jpg new file mode 100644 index 0000000..c463d9e Binary files /dev/null and b/assets/celebrate.jpg differ diff --git a/assets/celebrate2.jpg b/assets/celebrate2.jpg new file mode 100644 index 0000000..d26b1bb Binary files /dev/null and b/assets/celebrate2.jpg differ diff --git a/assets/hero.jpg b/assets/hero.jpg new file mode 100644 index 0000000..1622153 Binary files /dev/null and b/assets/hero.jpg differ diff --git a/css/styles.css b/css/styles.css index e69de29..8284b32 100644 --- a/css/styles.css +++ b/css/styles.css @@ -0,0 +1,462 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif; +} + +:root { + --gray: #f1f3f4; +} + +body { + display: flex; + flex-direction: column; + min-height: 100vh; + +} + +h2 { + font-size: 26px; +} + +h3 { + font-size: 22px; +} + +p { + font-size: 18px; +} + +.skip-link { + position: absolute; + top: -40px; + left: 0; + color: black; + padding: 8px; + z-index: 100; + transition: top 0.3s; + background-color: white; +} + +.skip-link:focus { + top: 0; + outline-offset: 2px; + border-radius: 2px; + text-decoration: none; +} + +:focus-visible { + outline: 2px solid yellow; + outline-offset: 2px; + border-radius: 2px; +} + +#header { + background-color: white; + color: black; + padding: 5px 7px; + display: flex; + align-items: flex-end; + min-height: 70px; + +} + +.header-content { + display: flex; + justify-content: space-between; + align-items: flex-end; + width: 100%; + height: 100%; + +} + + +h1 { + font-size: 32px; + +} + +ul { + display: flex; + gap: 10px; +} + +li { + list-style-type: none; + padding: 5px; +} + +.nav-links { + text-decoration: none; + color: black; + font-size: 18px; +} + +#banner { + height: auto; +} + +#banner img { + width: 100%; + object-fit: cover; + height: auto; + max-height: 250px; +} + +main { + background-color: white; + margin-top: -4px; + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + color: black; + +} + + + +/*About*/ +#about { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + flex: 1; + padding: 7px; + + +} + +.about-us { + padding: 20px; + background-color: var(--gray); + max-width: 446px; + border-radius: 10px; + +} + +.about-us p, +.about-us h2 { + margin: 5px; +} + +.our-team:not([hidden]) { + min-height: 600px; + display: flex; + flex-direction: column; + justify-content: space-evenly; +} + +.person { + background-color: var(--gray); + border-radius: 10px; + padding: 20px; + max-width: 600px; +} + +.person h3 { + font-weight: 300; +} + +.button-box { + padding-top: 10px; + display: flex; + width: 100%; + align-items: center; + justify-content: center; +} + +#team-link { + text-decoration: none; + color: white; +} + + + +/*Här gör vi disply flex för att styla introduction*/ +#introduction-section:not([hidden]) { + margin-top: -4px; + padding: 7px; + max-width: 446px; + display: flex; + align-items: center; + justify-content: center; +} + + + +#introduction-section h2, +#introduction-section p { + margin: 5px; +} + + +.introduction { + margin-top: 7px; + background-color: var(--gray); + border-radius: 10px; + padding: 20px; + +} + +#user-info:not([hidden]) { + padding: 10px; + margin-top: 7px; + border-radius: 10px; + max-width: 446px; + background-color: var(--gray); +} + +#user-info-form { + min-width: 280px; + min-height: 280px; + padding: 20px; + display: flex; + justify-content: space-between; + +} + +.error { + color: rgb(143, 3, 3); +} + +.form-control { + display: flex; + flex-direction: column; + gap: 5px; + height: 100%; + +} + +.form-control input { + font-size: 18px; + height: 40px; + border-radius: 7px; + padding: 5px; + border: none; +} + +.form-control input::placeholder { + color: #1d2e42; +} + +label { + font-size: 18px; + +} + +.continue-container { + display: flex; + justify-content: center; + padding: 10px 0; +} + + +#quiz-section:not([hidden]) { + display: flex; + flex-direction: column; + gap: 10px; + margin: 5px; +} + +.quiz-instructions { + padding: 10px; + border-radius: 10px; + +} + +/*progressbar*/ +.progress-bar-container:not([hidden]) { + width: 70%; + display: flex; + flex-direction: column; + align-self: center; + padding: 30px 0; + +} + +.bar { + height: 15px; + border-radius: 5px; + background-color: rgb(221, 221, 252) +} + +.progress-fill { + height: 100%; + background-color: rgb(13, 13, 111); + border-radius: 5px; + transition: all 0.25s ease-in-out; +} + +.progress-text { + margin-top: 10px; + text-align: center; +} + +form { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; + position: relative; +} + +legend { + font-size: 18px; + font-weight: 600; + font-style: italic; + text-align: center; +} + +.form-questions:not([hidden]) { + padding: 10px; + border-radius: 10px; + background-color: var(--gray); + border: none; + min-height: 300px; + width: 100%; + min-width: 100px; + max-width: 600px; + display: flex; + flex-direction: column; + gap: 10px; +} + +.question-border { + border: 1px solid black; + border-radius: 10px; + padding: 2px; + background-color: var(--gray); +} + + +.answer-container { + display: flex; + flex-direction: row; + gap: 20px; + padding: 5px; + margin: 10px 0; + background-color: white; + border-radius: 10px; + color: black; + font-size: 16px; + transition: 0.25s linear; +} + + + +.wrong-answers { + list-style-type: disc; + list-style-position: inside; +} + +.form-result:not([hidden]) { + background-color: white; + max-width: 500px; + background-color: var(--gray); + border-radius: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + + +#img-container h3 { + position: absolute; + text-align: center; + color: white; + font-size: 26px; + width: 100%; + +} + +.result-container { + padding: 10px; + width: 100%; + +} + +.form-result img { + width: 100%; + height: auto; + border-radius: 10px; +} + +#results-message { + font-size: 22px; +} + +#flunked h4 { + font-size: 18px; +} + +.answer-container:hover { + background-color: rgb(221, 221, 252) +} + +radio:focus-visible { + background-color: #0d151f; +} + +.button-container { + display: flex; + margin-top: 5px; + justify-content: space-between; +} + + +.quiz-buttons:not([hidden]), +.intro-continue { + min-width: 90px; + width: auto; + height: 50px; + font-size: 18px; + padding: 5px 10px; + border: none; + border-radius: 7px; + background-image: linear-gradient(to right, #27069b, #1b0c50); + color: white; + box-shadow: 0px 0px 10px 2px rgba(29, 46, 66, 0.3); + text-align: center; +} + +.quiz-buttons:not([hidden]):hover, +.intro-continue:hover { + background-image: linear-gradient(to right, #1a0473, #120833) +} + + +#previous-button[hidden] { + visibility: hidden; + display: block; +} + + +#footer { + background-color: white; + height: 70px; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-evenly; +} + +.footer-content { + padding: 0 10px; +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} \ No newline at end of file diff --git a/index.html b/index.html index a9a33db..0aa8607 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,494 @@ - - - - - Title - - - -

This is the starting point.

- - - + + + + + + Web Accessebility Quiz + + + + + + + + + + +
+ +
+
+

Introduction

+

Our quiz is designed with accessibility in mind, offering high contrast mode for readability, reduced motion + to minimize distractions, and full keyboard navigation. We also use semantic HTML and ARIA attributes to + ensure compatibility with screen readers, making the experience inclusive for all users. +

+
+ + +
+
+
+ + + + + + + + + + + +
+ + + + + + + + \ No newline at end of file diff --git a/js/accordion.js b/js/accordion.js new file mode 100644 index 0000000..ed8bb62 --- /dev/null +++ b/js/accordion.js @@ -0,0 +1,7 @@ +const teamSection = document.getElementById('our-team') +const teamButton = document.getElementById('team-button') + + +teamButton.addEventListener('click', () => { + teamSection.hidden = false +}) \ No newline at end of file diff --git a/js/main.js b/js/main.js index e69de29..24c283e 100644 --- a/js/main.js +++ b/js/main.js @@ -0,0 +1,352 @@ +//Question-cards +const formQuestions = Array.from(document.getElementsByClassName('form-questions')) +let index = 0 + +//Buttons +const resultButton = document.getElementById('result-button') +const retakeButton = document.getElementById('retake-button') +const resultsPage = document.getElementById('results') +const bar = document.getElementById('bar') +const instructions = document.getElementById('quiz-instructions') +const percent = document.getElementById('percent-bar') +const continueToQuiz = document.getElementById('intro-continue') +const backButton = document.getElementById('previous-button') +const nextButton = document.getElementById('next-button') +//const startQuiz = document.getElementById('start-quiz') + +const announcer = document.getElementById('announcer') +const nameInput = document.getElementById('name'); +const emailInput = document.getElementById('email'); +const nameError = document.getElementById('name-error'); +const emailError = document.getElementById('email-error'); +let userName = ''; +const radioErrorMessage = document.getElementById('answer-error') + + +//Sections +const introSection = document.getElementById('introduction-section') +const quizSection = document.getElementById('quiz-section') +const userInfoSection = document.getElementById('user-info') +const userInfoForm = document.getElementById('user-info-form'); +const quizForm = document.getElementById('quiz') + + +//progress bar +const progressContainer = document.getElementById('progress-bar-container') +const progressFill = document.querySelector('.progress-fill') +const progressText = document.querySelector('.progress-text') + +//array +const radioFour = Array.from(document.querySelectorAll('input[name="color-accessibility"]')) + +const pointTotal = 4 + + +//When we click continue to quiz +continueToQuiz.addEventListener('click', () => { + + introSection.hidden = true + userInfoSection.hidden = false + window.location.hash = '#user-info' + document.getElementById('name').focus() + announcer.textContent = 'Moved to user information section' + +}) + + +const clearError = (input, errorElement) => { + input.removeAttribute('aria-invalid'); + errorElement.textContent = ''; + errorElement.hidden = true; +} + +const showError = (input, errorElement, message) => { + input.setAttribute('aria-invalid', 'true'); + errorElement.textContent = message; + errorElement.hidden = false; +} + +const isValidEmail = (email) => { + return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); +} + + +nameInput.addEventListener('input', () => { + if (nameInput.value.trim()) { + clearError(nameInput, nameError); + } +}); + +emailInput.addEventListener('input', () => { + if (emailInput.value.trim()) { + if (isValidEmail(emailInput.value)) { + clearError(emailInput, emailError); + } + } +}); + +//When we click continue to quiz + +userInfoForm.addEventListener('submit', (e) => { + e.preventDefault() + + const currentQuestion = formQuestions[0] + currentQuestion.hidden = false + retakeButton.hidden = true + nextButton.hidden = false + + + + let isValid = true; + + if (!nameInput.value.trim()) { + showError(nameInput, nameError, 'Please enter your name'); + isValid = false; + nameInput.focus(); + } else { + clearError(nameInput, nameError); + } + + if (!emailInput.value.trim()) { + showError(emailInput, emailError, 'Please enter your email address'); + isValid = false; + if (!nameError.textContent) { + emailInput.focus(); + } + } else if (!isValidEmail(emailInput.value.trim())) { + showError(emailInput, emailError, 'Please enter a valid email address'); + isValid = false; + if (!nameError.textContent) { + emailInput.focus(); + } + } else { + clearError(emailInput, emailError); + } + + if (isValid) { + userName = nameInput.value.trim(); + userInfoSection.hidden = true + quizSection.hidden = false + quizSection.scrollIntoView({ behavior: 'smooth' }); + document.querySelector('#quiz input[type="radio"]').focus(); + announcer.textContent = 'Moved to quiz section'; + } + + document.getElementById('question-1-1').focus() + //quizForm.querySelector('input[type="radio"]').focus() +}) +//when we click start quiz + +const isChecked = (array) => { + const checked = array.some(item => item.checked) + if (!checked) { + radioErrorMessage.hidden = false + radioErrorMessage.textContent = "you have to choose an answer" + announcer.textContent = 'you have to choose an answer' + } else { + radioErrorMessage.hidden = true; + } + return checked +} + + + +//function that ensures the right buttons and questions are showing at the right time +const showNextQuestion = (i) => { + const currentQuestion = formQuestions[i] + const nextQuestion = formQuestions[(i + 1) % formQuestions.length] + let radioArray = Array.from(currentQuestion.querySelectorAll('input[type="radio"]')) + + if (i >= (formQuestions.length - 1)) { + return + } else if (i >= 0) { + + if (!isChecked(radioArray)) { + return + + + } else { + + backButton.removeAttribute('hidden') + nextQuestion.removeAttribute('hidden') + currentQuestion.setAttribute('hidden', true) + } + + if (i === formQuestions.length - 2) { + nextButton.setAttribute('hidden', true) + resultButton.removeAttribute('hidden') + } + + index += 1 + + document.getElementById('question-2-1').focus() + document.getElementById('question-3-1').focus() + document.getElementById('question-4-1').focus() + announcer.textContent = 'Moved to next question' + } +} + +const showPrevQuestion = (i) => { + radioErrorMessage.hidden = true + + if (i >= 1) { + + const currentQuestion = formQuestions[i] + const prevQuestion = formQuestions[(i - 1) % formQuestions.length] + + currentQuestion.setAttribute('hidden', true) + prevQuestion.removeAttribute('hidden') + + if (i === formQuestions.length - 1) { + resultButton.setAttribute('hidden', true) + nextButton.removeAttribute('hidden') + } + if (i === 1) { + backButton.setAttribute('hidden', true) + } + } + + index -= 1 + announcer.textContent = 'Moved to previous question'; + +} + +const countScore = () => { + let points = document.querySelectorAll('input[value="true"]:checked') + console.log("here is:", points) + return points.length +} + +const WrongQuestionCount = () => { + let points = document.querySelectorAll('input[value="false"]:checked') + return points.length +} + +const wrongQuestions = () => { + let questions = document.querySelectorAll('input[value="false"]:checked') + let question = [] + + let falseQuestions = [] + questions.forEach(question => { + falseQuestions.push(question.parentElement.parentElement.id) + }) + + for (i = 0; falseQuestions[i]; i++) { + question[i] = `question ${i + 1}` + } + console.log(question) + return question +} + +const updateProgress = () => { + let points = (countScore() + WrongQuestionCount()) + const percentage = (points / pointTotal) * 100; + console.log(percentage) + + progressFill.style.width = `${percentage}%`; + progressText.textContent = `${points}/${pointTotal} sections completed`; + announcer.textContent = `${points} of ${pointTotal} sections completed`; +} + +quizForm.querySelectorAll('input[type="radio"]').forEach((radio) => { + radio.addEventListener('change', () => { + updateProgress() + }) +}) +//each input has an event listener cuasing a update + + +const showResults = (i) => { + const score = document.getElementById('score') + const flunked = document.getElementById('flunked') + const resultsMessage = document.getElementById('results-message') + const currentQuestion = formQuestions[i] + let points = countScore() + let questions = wrongQuestions() + + let selected = (document.querySelectorAll('input[value="true"]:checked').length + document.querySelectorAll('input[value="false"]:checked').length) + + + + + backButton.setAttribute('hidden', true) + nextButton.setAttribute('hidden', true) + resultButton.setAttribute('hidden', true) + currentQuestion.setAttribute('hidden', true) + resultsPage.removeAttribute('hidden') + retakeButton.removeAttribute('hidden') + + progressContainer.hidden = true + progressText.hidden = true + instructions.hidden = true + + announcer.textContent = 'Moved to result page' + + if (points < pointTotal) { + flunked.innerHTML = `

Questions you got wrong are:

` + + + } else { + flunked.innerHTML = '' + } + + score.innerHTML = `Your score is: ${points}/${pointTotal}` + + if (points === 0) { + resultsMessage.innerHTML = 'Yikes...' + } else if (points === 1) { + resultsMessage.innerHTML = 'This speaks for itself' + } else if (points === 2) { + resultsMessage.innerHTML = 'Wow. Half' + } else if (points === 3) { + resultsMessage.innerHTML = 'Close, but not quite' + } else if (points === pointTotal) { + resultsMessage.innerHTML = 'Winner, winner chicken dinner' + } +} + +nextButton.addEventListener(('click'), () => { + showNextQuestion(index) +}) + +backButton.addEventListener(('click'), () => { + showPrevQuestion(index) +}) + +quizForm.addEventListener(('submit'), (event) => { + event.preventDefault() + if (!isChecked(radioFour)) { + return + } else { + showResults(index) + } +}) + +retakeButton.addEventListener(('click'), () => { + resultsPage.hidden = true + index = 0 + introSection.hidden = false + retakeButton.hidden = false + quizSection.hidden = true + + //Visa quiz section (tror jag) och cleara svaren sen tidigare + + /* + let infoInput = [document.getElementById('name'), document.getElementById('email')] + infoInput.forEach((input) => { + input.value = '' + }) + // clearing name and email input + */ + + document.querySelector('input[name="web-accessibility"]:checked').checked = false; + document.querySelector('input[name="WCAG"]:checked').checked = false; + document.querySelector('input[name="cognitive-disability"]:checked').checked = false; + document.querySelector('input[name="color-accessibility"]:checked').checked = false; + //clearing marked radio buttons + + progressFill.style.width = `0%` + //clearing progress bar + continueToQuiz.focus() + +})