diff --git a/docs/index.html b/docs/index.html index baaf90c6..0a4228d0 100644 --- a/docs/index.html +++ b/docs/index.html @@ -26,6 +26,9 @@

MA Projects

  • Rostyslav Vyshemirskyi - Final Project
  • +
  • + Max Snischuk - Final Project +
  • diff --git a/docs/snischuk/calculator.html b/docs/snischuk/calculator.html new file mode 100644 index 00000000..fcc18080 --- /dev/null +++ b/docs/snischuk/calculator.html @@ -0,0 +1,99 @@ + + + + + + + + Calculator + + +
    + +
    +
    +
    +

    Calculate pokemons

    +
    + + + + +
    + +

    +
    +
    + + + + + \ No newline at end of file diff --git a/docs/snischuk/images/about.jpeg b/docs/snischuk/images/about.jpeg new file mode 100644 index 00000000..ea741e9a Binary files /dev/null and b/docs/snischuk/images/about.jpeg differ diff --git a/docs/snischuk/images/favicon.ico b/docs/snischuk/images/favicon.ico new file mode 100644 index 00000000..52f1ccc8 Binary files /dev/null and b/docs/snischuk/images/favicon.ico differ diff --git a/docs/snischuk/images/icon-check-filter.svg b/docs/snischuk/images/icon-check-filter.svg new file mode 100644 index 00000000..09a7d36c --- /dev/null +++ b/docs/snischuk/images/icon-check-filter.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/snischuk/images/icon-check-login.svg b/docs/snischuk/images/icon-check-login.svg new file mode 100644 index 00000000..df2b5929 --- /dev/null +++ b/docs/snischuk/images/icon-check-login.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/snischuk/images/icon-radio-filter.svg b/docs/snischuk/images/icon-radio-filter.svg new file mode 100644 index 00000000..230ada03 --- /dev/null +++ b/docs/snischuk/images/icon-radio-filter.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/snischuk/images/icon-search.svg b/docs/snischuk/images/icon-search.svg new file mode 100644 index 00000000..9de72d3f --- /dev/null +++ b/docs/snischuk/images/icon-search.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/snischuk/images/icon-select-arrow.svg b/docs/snischuk/images/icon-select-arrow.svg new file mode 100644 index 00000000..17bfb553 --- /dev/null +++ b/docs/snischuk/images/icon-select-arrow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/snischuk/images/logo.svg b/docs/snischuk/images/logo.svg new file mode 100644 index 00000000..26be4196 --- /dev/null +++ b/docs/snischuk/images/logo.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/docs/snischuk/images/urshifu.png b/docs/snischuk/images/urshifu.png new file mode 100644 index 00000000..40de7e9c Binary files /dev/null and b/docs/snischuk/images/urshifu.png differ diff --git a/docs/snischuk/index.html b/docs/snischuk/index.html new file mode 100644 index 00000000..c14d975c --- /dev/null +++ b/docs/snischuk/index.html @@ -0,0 +1,111 @@ + + + + + + + + + + About + + +
    + +
    +
    +
    + pokemon +
    +

    About me

    +

    + Hi! My name is Max and I'm a Junior Frontend Developer. I am already + familiar with main Web Technologies like HTML, CSS, JavaScript and + Git version control system. +

    +

    + This page was developed during the course + + 'Frontend for beginners' from Masters Academy in 2023. + +

    +

    + This is a social project from MOCG company where I got an + opportunity to work with Frontend mentors and to create my own small + project for the portfolio. +

    +

    + You can contact me via + Telegram + and/or check out my + GitHub. +

    +
    +
    +
    + + + \ No newline at end of file diff --git a/docs/snischuk/login-success.html b/docs/snischuk/login-success.html new file mode 100644 index 00000000..38f616e2 --- /dev/null +++ b/docs/snischuk/login-success.html @@ -0,0 +1,84 @@ + + + + + + + + + + Login page + + +
    + +
    +
    + +

    Login successful!

    +

    You have successfully signed into your account. You can return to home page and + continue using the platform.

    + Return to Home +
    + + + \ No newline at end of file diff --git a/docs/snischuk/login.html b/docs/snischuk/login.html new file mode 100644 index 00000000..7acd4746 --- /dev/null +++ b/docs/snischuk/login.html @@ -0,0 +1,98 @@ + + + + + + + + + + Login page + + +
    + +
    +
    +
    + + + + + + + +
    +
    + + + + \ No newline at end of file diff --git a/docs/snischuk/pokemons.html b/docs/snischuk/pokemons.html new file mode 100644 index 00000000..e1341ba1 --- /dev/null +++ b/docs/snischuk/pokemons.html @@ -0,0 +1,118 @@ + + + + + + + + + + Pokemons + + +
    + +
    +
    +
    +
    +
    + +
      +
    • Grass
    • +
    • Poison
    • +
    • Electric
    • +
    • Psychic
    • +
    • Fire
    • +
    • Flying
    • +
    • Water
    • +
    • Bug
    • +
    • Normal
    • +
    +
    +
    + + + + +
    + +
    +
    +
    +
    +

    Study project "Pokemons"

    +
      +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/docs/snischuk/scripts/calculate.js b/docs/snischuk/scripts/calculate.js new file mode 100644 index 00000000..29ed2965 --- /dev/null +++ b/docs/snischuk/scripts/calculate.js @@ -0,0 +1,39 @@ +function calculate(firstValue, secondValue, operation) { + let result; + const firstNumber = Number(firstValue); + const secondNumber = Number(secondValue); + + if (firstValue === '' || secondValue === '') return 'Enter a number'; + if (Number.isNaN(firstNumber) || Number.isNaN(secondNumber)) return 'Enter a number'; + + switch (operation) { + case '+': + result = firstNumber + secondNumber; + break; + case '-': + result = firstNumber - secondNumber; + break; + case '*': + result = firstNumber * secondNumber; + break; + case '/': + if (secondNumber === 0) { + result = 'You can\'t divide by zero'; + break; + } + + result = Number.parseFloat((firstNumber / secondNumber).toFixed(2)); + break; + default: + result = 'Choose a valid operation'; + break; + } + + if (result > 100) return 'Too many pokemons'; + + if (result > 1) return `${result} pokemons`; + + return `${result} pokemon`; +} + +window.calculate = calculate; diff --git a/docs/snischuk/scripts/pokemons.js b/docs/snischuk/scripts/pokemons.js new file mode 100644 index 00000000..b40143eb --- /dev/null +++ b/docs/snischuk/scripts/pokemons.js @@ -0,0 +1,221 @@ +async function initPokemons() { + const body = document.querySelector('body'); + const FORM_FILTERS_ELEMENT = document.querySelector('[data-form-filters]'); + const SELECT_CUSTOM_BTN = FORM_FILTERS_ELEMENT.querySelector('[data-select-custom-btn]'); + const SELECT_CUSTOM_LIST = FORM_FILTERS_ELEMENT.querySelector('[data-select-custom-list]'); + const TEXT_INPUT_ELEMENT = FORM_FILTERS_ELEMENT.elements['search-query']; + const CARDS_CONTAINER_ELEMENT = document.querySelector('[data-cards-container]'); + const LOADER_CONTAINER_ELEMENT = document.querySelector('[data-loader-container]'); + + const selectCustomOptions = Array.from(SELECT_CUSTOM_LIST.querySelectorAll('[data-option-value]')); + + let allCards; + let filteredCards = []; + + function getSelectedOptionsValues() { + return selectCustomOptions.filter((option) => option.classList.contains('filters__select-option--selected')) + .map((option) => option.dataset.optionValue); + } + + function toggleSelectedOptionHandler(event) { + selectCustomOptions.forEach((option) => { + if (event.target !== option) return; + option.classList.toggle('filters__select-option--selected'); + }); + } + + function hideDropDownOptions(event) { + event.stopPropagation(); + if (event.target.tagName === 'LI') return; + SELECT_CUSTOM_LIST.classList.remove('filters__select-list--active'); + body.removeEventListener('click', hideDropDownOptions); + } + + function showDropDownOptions(event) { + event.stopPropagation(); + SELECT_CUSTOM_LIST.classList.add('filters__select-list--active'); + body.addEventListener('click', hideDropDownOptions); + } + + function initCustomSelect() { + SELECT_CUSTOM_BTN.addEventListener('click', showDropDownOptions); + SELECT_CUSTOM_LIST.addEventListener('click', toggleSelectedOptionHandler); + } + + function clearContainer(container) { + if (!container) return; + container.innerHTML = ''; + } + + function showLoader() { + const LOADER_ELELEMNT = ` +
      +

      Loading...

      + `; + LOADER_CONTAINER_ELEMENT.innerHTML = LOADER_ELELEMNT; + } + + function hideLoader() { + clearContainer(LOADER_CONTAINER_ELEMENT); + } + + function createCardElement(pokemon) { + const { + name, + ThumbnailImage, + ThumbnailAltText, + height, + weight, + number, + type, + weakness, + } = pokemon; + + const typesTags = type + .map((subtype) => `${subtype.charAt(0).toUpperCase()}${subtype.toLowerCase().slice(1)}`) + .join(''); + + const weaknessesTags = weakness + .map((subtype) => `${subtype}`) + .join(''); + + const cardTemplateStr = ` +
    • +
      + ${ThumbnailAltText} +

      ${name}

      +
      + +
    • + `; + + return cardTemplateStr; + } + + function renderCards(container, cards) { + clearContainer(container); + + const renderedCards = cards.map((card) => { + const pokemonCard = createCardElement(card); + container.insertAdjacentHTML('beforeEnd', pokemonCard); + return pokemonCard; + }); + + return renderedCards; + } + + function filterByPokemonsType(cards) { + const selectedOptionsValues = getSelectedOptionsValues(); + + const filteredTypes = cards.filter((card) => selectedOptionsValues + .every((type) => card.type.includes(type))); + + return filteredTypes; + } + + function filterBySearchQuery(cards) { + const inputValue = FORM_FILTERS_ELEMENT.elements['search-query'].value.toLowerCase(); + return cards.filter((card) => card.name.toLowerCase().includes(inputValue)); + } + + function sortByHeight(cards) { + const isLowFirstChecked = FORM_FILTERS_ELEMENT.elements.low.checked; + + const sortedCards = cards.sort((a, b) => { + if (isLowFirstChecked) { + return a.height - b.height; + } + return b.height - a.height; + }); + + return sortedCards; + } + + function updateFilteredCards() { + filteredCards = [...allCards]; + + if (FORM_FILTERS_ELEMENT.querySelector('[data-select-custom-btn]')) { + filteredCards = filterByPokemonsType(filteredCards); + } + + if (FORM_FILTERS_ELEMENT.elements['search-query'].value) { + filteredCards = filterBySearchQuery(filteredCards); + } + + if (FORM_FILTERS_ELEMENT.elements['sort-height'].value) { + filteredCards = sortByHeight(filteredCards); + } + + return filteredCards; + } + + function onChangeFiltersHandler() { + const updatedFilteredCards = updateFilteredCards(); + renderCards(CARDS_CONTAINER_ELEMENT, updatedFilteredCards); + } + + function onInputSearchHandler() { + const updatedFilteredCards = updateFilteredCards(); + renderCards(CARDS_CONTAINER_ELEMENT, updatedFilteredCards); + } + + function onSubmitFiltersHandler(event) { + event.preventDefault(); + onChangeFiltersHandler(); + } + + function onClickCustomSelectHandler() { + const updatedFilteredCards = updateFilteredCards(); + renderCards(CARDS_CONTAINER_ELEMENT, updatedFilteredCards); + } + + async function fetchPokemons() { + try { + showLoader(); + + const pokemonsUrl = 'https://my-json-server.typicode.com/electrovladyslav/pokemon-json-server/pokemons'; + const options = { + method: 'GET', + }; + + const response = await fetch(`${pokemonsUrl}`, options); + + return await response.json(); + } catch (error) { + console.error(`GET error: ${error.message}`); + CARDS_CONTAINER_ELEMENT.innerHTML = `GET error: ${error.message}... Please try again later.`; + } finally { + hideLoader(); + } + } + + initCustomSelect(); + + allCards = await fetchPokemons(); + renderCards(CARDS_CONTAINER_ELEMENT, allCards); + + TEXT_INPUT_ELEMENT.addEventListener('input', onInputSearchHandler); + FORM_FILTERS_ELEMENT.addEventListener('change', onChangeFiltersHandler); + SELECT_CUSTOM_LIST.addEventListener('click', onClickCustomSelectHandler); + FORM_FILTERS_ELEMENT.addEventListener('submit', onSubmitFiltersHandler); +} + +document.addEventListener('DOMContentLoaded', initPokemons); diff --git a/docs/snischuk/scripts/script.js b/docs/snischuk/scripts/script.js new file mode 100644 index 00000000..fda50b19 --- /dev/null +++ b/docs/snischuk/scripts/script.js @@ -0,0 +1,249 @@ +const FIRST_VALUE_ELEMENT = document.querySelector('[data-math-value="first"]'); +const SECOND_VALUE_ELEMENT = document.querySelector('[data-math-value="second"]'); +const OPERATION_ELEMENT = document.querySelector('[data-math-operation]'); +const CALCULATE_BUTTON_ELEMENT = document.querySelector('[data-math-calculate-btn]'); +const RESULT_VALUE_ELEMENT = document.querySelector('[data-math-output-value]'); +const CALCULATOR_CONTAINER = document.querySelector('[data-math-container]'); +const CALCULATOR_TIME = document.querySelector('[data-math-time]'); + +const MIN_CARDS_IN_COLUMN = 1; +const MAX_CARDS_IN_COLUMN = 10; + +function measureTimeFn(fn) { + const start = Date.now(); + for (let i = 0; i < 100; i++) { + fn(); + } + const finish = Date.now(); + const duration = finish - start; + + return `Time of function execution: ${duration}ms`; +} + +function formatCustomDate(date) { + const year = date.getFullYear(); + const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + const month = monthNames[date.getMonth()]; + let dayOfMonth = date.getDate(); + let hour = date.getHours(); + let minutes = date.getMinutes(); + + dayOfMonth = dayOfMonth < 10 ? `0${dayOfMonth}` : dayOfMonth; + hour = hour < 10 ? `0${hour}` : hour; + minutes = minutes < 10 ? `0${minutes}` : minutes; + + return `Date of calculation: ${dayOfMonth}-${month}-${year}, ${hour}:${minutes}.`; +} + +function deleteMathExpression() { + const MATH_EXPRESSION_ELEMENT = CALCULATOR_CONTAINER.querySelector('[data-math-output-list]'); + if (!MATH_EXPRESSION_ELEMENT) return; + MATH_EXPRESSION_ELEMENT.remove(); +} + +function createMathExpressionElement(value1, sign, value2, result) { + return ` + + `; +} + +function renderMathExpressionElement() { + deleteMathExpression(); + + const firstValue = Number.parseFloat(FIRST_VALUE_ELEMENT.value); + const secondValue = Number.parseFloat(SECOND_VALUE_ELEMENT.value); + const operation = OPERATION_ELEMENT.value; + + if (Number.isNaN(firstValue) || Number.isNaN(secondValue)) { + RESULT_VALUE_ELEMENT.innerText = 'Enter a number'; + return; + } + + const mathResult = window.calculate(firstValue, secondValue, operation); + RESULT_VALUE_ELEMENT.innerText = mathResult; + + CALCULATOR_CONTAINER.insertAdjacentHTML('beforeend', createMathExpressionElement(firstValue, operation, secondValue, mathResult)); +} + +function clearElement(element) { + if (!element) return; + element.innerHTML = ''; +} + +function changeElement(fromElement, toElement) { + if (!(fromElement instanceof Element) || !(toElement instanceof Element)) return; + fromElement.outerHTML = toElement.outerHTML; +} + +function addElement(parent, child) { + if (!(parent instanceof Element) || !(child instanceof Element)) return; + parent.appendChild(child); +} + +function createCard() { + const card = document.createElement('li'); + card.classList.add('calculator__math-output-card'); + + const cardTemplate = ` +
      +
      + urshifu +

      Urshifu

      +
      + +
      + `; + + card.innerHTML = cardTemplate; + return card; +} + +function createPartialCard(size) { + const pokemonCard = createCard(); + pokemonCard.style.clipPath = `inset(0 0 ${100 - size * 100}% 0)`; + return pokemonCard; +} + +function addCardsToList(count) { + const pokemonsCardsList = document.createElement('ul'); + pokemonsCardsList.classList.add('calculator__column'); + + for (let i = 1; i <= count; i++) { + const pokemonCard = createCard(); + pokemonsCardsList.appendChild(pokemonCard); + } + + const partialCardSize = count - Math.floor(count); + if (partialCardSize > 0) { + const partialCard = createPartialCard(partialCardSize); + pokemonsCardsList.appendChild(partialCard); + } + + return pokemonsCardsList; +} + +function overlapStyle(cardsCount, gridContainer) { + const fullCountRow = Math.ceil(Number(cardsCount)); + if (!(gridContainer instanceof Element) || fullCountRow < 0) return; + gridContainer.style.gridTemplateRows = `repeat(${fullCountRow + 1}, 80px)`; +} + +function firstOutputOperandHandler() { + const MATH_FIRST_OPERAND_ELEMENT = document.querySelector('[data-math-operand="first"]'); + const pokemonsCardsCount = FIRST_VALUE_ELEMENT.value; + + if (pokemonsCardsCount < 0) { + deleteMathExpression(); + return; + } + + if (pokemonsCardsCount === 0) { + MATH_FIRST_OPERAND_ELEMENT.innerHTML = 0; + } + + if (pokemonsCardsCount > 0 && pokemonsCardsCount < MIN_CARDS_IN_COLUMN) { + clearElement(MATH_FIRST_OPERAND_ELEMENT); + + const partialCardSize = pokemonsCardsCount; + const partialCard = createPartialCard(partialCardSize); + + changeElement(MATH_FIRST_OPERAND_ELEMENT, partialCard); + return; + } + + if (pokemonsCardsCount >= MIN_CARDS_IN_COLUMN && pokemonsCardsCount <= MAX_CARDS_IN_COLUMN) { + clearElement(MATH_FIRST_OPERAND_ELEMENT); + + const cardsList = addCardsToList(pokemonsCardsCount); + overlapStyle(pokemonsCardsCount, cardsList); + + addElement(MATH_FIRST_OPERAND_ELEMENT, cardsList); + + MATH_FIRST_OPERAND_ELEMENT.style.paddingBottom = '280px'; + } +} + +function lastOutputOperandHandler() { + const LIMIT_CARDS = 100; + const MATH_LAST_OPERAND_ELEMENT = document.querySelector('[data-math-operand="last"]'); + + const pokemonsCountResult = Number.parseFloat(RESULT_VALUE_ELEMENT.innerText); + + if (pokemonsCountResult <= 0) { + deleteMathExpression(); + return; + } + + if (pokemonsCountResult < MIN_CARDS_IN_COLUMN) { + clearElement(MATH_LAST_OPERAND_ELEMENT); + + const partialCardSize = pokemonsCountResult; + const partialCard = createPartialCard(partialCardSize); + + changeElement(MATH_LAST_OPERAND_ELEMENT, partialCard); + return; + } + + if (pokemonsCountResult >= MIN_CARDS_IN_COLUMN && pokemonsCountResult <= LIMIT_CARDS) { + clearElement(MATH_LAST_OPERAND_ELEMENT); + + const columnCount = Math.ceil(pokemonsCountResult / MAX_CARDS_IN_COLUMN); + let remainingCards = pokemonsCountResult; + + for (let i = 1; i <= columnCount; i++) { + const cardsInCurrentColumn = Math.min(MAX_CARDS_IN_COLUMN, remainingCards); + + const cardsList = addCardsToList(cardsInCurrentColumn); + overlapStyle(cardsInCurrentColumn, cardsList); + + addElement(MATH_LAST_OPERAND_ELEMENT, cardsList); + remainingCards -= cardsInCurrentColumn; + } + + MATH_LAST_OPERAND_ELEMENT.style.paddingBottom = '280px'; + } +} + +function clickCalculateBtnHandler() { + const measuredTime = measureTimeFn(renderMathExpressionElement); + const dateCalculation = formatCustomDate(new Date()); + CALCULATOR_TIME.innerHTML = `${dateCalculation} ${measuredTime}`; +} + +function inputFirstValueHandler() { + renderMathExpressionElement(); + firstOutputOperandHandler(); + + const measuredTime = measureTimeFn(lastOutputOperandHandler); + const dateCalculation = formatCustomDate(new Date()); + CALCULATOR_TIME.innerHTML = `${dateCalculation} ${measuredTime}`; +} + +CALCULATE_BUTTON_ELEMENT.addEventListener('click', clickCalculateBtnHandler); +FIRST_VALUE_ELEMENT.addEventListener('input', inputFirstValueHandler); diff --git a/docs/snischuk/scripts/validate-form.js b/docs/snischuk/scripts/validate-form.js new file mode 100644 index 00000000..2b6aab95 --- /dev/null +++ b/docs/snischuk/scripts/validate-form.js @@ -0,0 +1,86 @@ +const EMAIL_INPUT_ID = 'email'; +const PASSWORD_INPUT_ID = 'password'; +const NOT_A_ROBOT_CHECKBOX_ID = 'checkbox'; +const SUBMIT_BUTTON_ID = 'submit'; +const RESULT_PAGE_PATH = './login-success.html'; + +const submitButton = document.getElementById(SUBMIT_BUTTON_ID); + +function getValueById(elementId) { + const element = document.getElementById(elementId); + const type = element.getAttribute('type'); + return type === 'checkbox' ? element.checked : element.value; +} + +function setErrors(inputId, errorMessage) { + const inputElement = document.getElementById(inputId); + const associatedLabels = inputElement.labels; + + const errorElement = document.createElement('p'); + errorElement.classList.add('error'); + errorElement.setAttribute('data-error', ''); + errorElement.textContent = errorMessage; + + associatedLabels[0].insertAdjacentElement('afterend', errorElement); +} + +function deleteErrors() { + const errorElement = document.querySelectorAll('[data-error]'); + errorElement.forEach((element) => element.remove()); +} + +function navigateToResultPage() { + window.location.href = RESULT_PAGE_PATH; +} + +function isEmail(email) { + return /\S+@\S+\.\S+/.test(email); +} + +function trimEmail(email) { + return email.replace(/\s/g, ''); +} + +function isPassword(password) { + const trimmedPassword = password.trim(); + return trimmedPassword.length >= 8 && trimmedPassword.length <= 12; +} + +function isChecked(checkboxFlag) { + return checkboxFlag; +} + +function validateForm() { + deleteErrors(); + + const errorMessages = { + [EMAIL_INPUT_ID]: 'Please fill in the correct email (format example: email@localdomen.domen)', + [PASSWORD_INPUT_ID]: 'Oops... The password length should be in the range of 8 to 12 characters.', + [NOT_A_ROBOT_CHECKBOX_ID]: 'Are you a robot? Click on the checkbox!', + }; + + const formValues = { + [EMAIL_INPUT_ID]: getValueById(EMAIL_INPUT_ID), + [PASSWORD_INPUT_ID]: getValueById(PASSWORD_INPUT_ID), + [NOT_A_ROBOT_CHECKBOX_ID]: getValueById(NOT_A_ROBOT_CHECKBOX_ID), + }; + + let hasErrors = false; + + Object.entries(formValues).forEach(([inputId, value]) => { + const isValid = (inputId === EMAIL_INPUT_ID && isEmail(trimEmail(value))) + || (inputId === PASSWORD_INPUT_ID && isPassword(value)) + || (inputId === NOT_A_ROBOT_CHECKBOX_ID && isChecked(value)); + + if (!isValid) { + setErrors(inputId, errorMessages[inputId]); + hasErrors = true; + } + }); + + if (!hasErrors) { + navigateToResultPage(); + } +} + +submitButton.onclick = validateForm; diff --git a/docs/snischuk/styles/about.css b/docs/snischuk/styles/about.css new file mode 100644 index 00000000..e55896e0 --- /dev/null +++ b/docs/snischuk/styles/about.css @@ -0,0 +1,64 @@ +@import "./base.css"; +@import "./header.css"; +@import "./footer.css"; + +.about { + padding: 30px 0; +} + +.about__container { + min-width: 300px; + max-width: 1280px; + padding: 0 var(--padding-container); + margin: 0 auto; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); + column-gap: 68px; + row-gap: 30px; +} + +.about__image { + width: 100%; + max-width: 532px; + object-fit: contain; +} + +.about__content { + display: grid; + grid-template-columns: 1fr; + row-gap: 16px; +} + +.about__title { + color: var(--color-dark); + font-size: 48px; + line-height: 52px; + font-weight: 700; +} + +.about__text { + color: var(--color-dark); + font-size: 22px; + line-height: 32px; + font-weight: 400; +} + +.about__link { + color: var(--color-accent); + transition: color .3s ease-in-out; +} + +.about__link:hover { + color: #3354FA; +} + +@media (min-width: 769px) { + + .about { + padding: 60px 0; + } + + .about__content { + row-gap: 32px; + } +} \ No newline at end of file diff --git a/docs/snischuk/styles/base.css b/docs/snischuk/styles/base.css new file mode 100644 index 00000000..f835c631 --- /dev/null +++ b/docs/snischuk/styles/base.css @@ -0,0 +1,35 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html, +body { + height: 100%; +} + +body { + font-family: Roboto, sans-serif; + display: flex; + flex-direction: column; +} + +main { + flex-grow: 1; +} + +:root { + --color-dark: #221F1F; + --color-light: #FFF; + --color-accent: #EF4934; + + --padding-container: 16px; +} + +@media (min-width: 769px) { + + :root { + --padding-container: 50px; + } +} \ No newline at end of file diff --git a/docs/snischuk/styles/calculator.css b/docs/snischuk/styles/calculator.css new file mode 100644 index 00000000..8e725441 --- /dev/null +++ b/docs/snischuk/styles/calculator.css @@ -0,0 +1,199 @@ +@import "./base.css"; +@import "./header.css"; +@import "./footer.css"; +@import "./card.css"; + +.calculator { + padding: 30px 0; +} + +.calculator__container { + min-width: 300px; + max-width: 1280px; + padding: 0 var(--padding-container); + margin: 0 auto; + display: flex; + flex-direction: column; + gap: 30px; +} + +.calculator__title { + text-align: center; + color: var(--color-dark); + font-size: 42px; + line-height: 52px; + font-weight: 700; +} + +.calculator__field { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: center; + justify-content: center; +} + +.calculator__time { + text-align: center; + color: var(--color-dark); + font-size: 18px; + line-height: 21px; +} + +.calculator__input { + max-width: 250px; + width: 100%; + padding: 20px; + border-radius: 6px; + border: 1px solid #A9A9A9; + background: var(--color-light); + color: var(--color-dark); + font-family: Roboto; + font-size: 14px; + line-height: 21px; + font-weight: 400; + transition: all .3s ease-in-out; +} + +.calculator__input::placeholder { + color: #A9A9A9; + font-family: Roboto; + font-size: 14px; + line-height: 21px; + font-weight: 400; +} + +.calculator__input:hover, +.calculator__input:focus { + outline: none; + border-bottom: 1px solid var(--color-accent); +} + +.calculator__select-math-sign { + max-width: 250px; + width: 100%; + height: 100%; + padding: 17px 20px; + border-radius: 6px; + border: 1px solid #A9A9A9; + background: var(--color-light); + font-family: Roboto; + color: var(--color-dark); + font-size: 22px; + line-height: normal; + font-weight: 600; + transition: all .3s ease-in-out; +} + +.calculator__select-math-sign:hover, +.calculator__select-math-sign:focus { + outline: none; + border-bottom: 1px solid var(--color-accent); +} + +.calculator__btn { + max-width: 250px; + width: 100%; + cursor: pointer; + padding: 20px; + border: none; + border-radius: 6px; + background: var(--color-accent); + box-shadow: 0 4px 30px 0 rgba(38, 58, 67, .15); + color: var(--color-light); + font-family: Roboto; + font-size: 22px; + line-height: normal; + font-weight: 600; + transition: filter .3s ease-in-out; +} + +.calculator__btn:hover { + filter: brightness(.9); +} + +.calculator__math-output { + text-align: center; + font-size: 22px; + line-height: 32px; + font-weight: 400; +} + +.calculator__math-output-list { + list-style: none; + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + gap: 30px; + flex-direction: column; +} + +.calculator__column { + list-style: none; + display: grid; + grid-template-columns: 1fr; +} + +.calculator__math-output-item { + color: var(--color-accent); + font-size: 36px; + line-height: 40px; + font-weight: 700; + column-gap: 20px; + row-gap: 250px; + display: flex; + flex-wrap: wrap; + justify-content: center; + align-content: center; +} + +.calculator__math-output-cards { + list-style: none; +} + +.calculator__math-output-card { + color: var(--color-accent); + font-size: 48px; + line-height: 32px; + font-weight: 700; + width: 255px; + height: 355px; +} + +@media (min-width: 768px) { + + .calculator { + padding: 60px 0; + } + + .calculator__container { + gap: 60px; + } + + .calculator__title { + font-size: 48px; + line-height: 48px; + } + + .calculator__input { + padding: 30px 20px; + } + + .calculator__select-math-sign { + padding: 27px 20px; + } + + .calculator__btn { + padding: 30px 20px; + } + + .calculator__math-output-list { + flex-direction: row; + } + + .calculator__math-output-item { + font-size: 48px; + line-height: 52px; + } +} \ No newline at end of file diff --git a/docs/snischuk/styles/card.css b/docs/snischuk/styles/card.css new file mode 100644 index 00000000..bbf2b160 --- /dev/null +++ b/docs/snischuk/styles/card.css @@ -0,0 +1,117 @@ +.card-pokemon { + width: 100%; + padding: 22px 12px; + background-color: #ECECEC; + border-radius: 12px; + box-shadow: 0 0 6px rgba(0, 0, 0, .25); + display: grid; + grid-template-columns: 1fr; + grid-template-rows: 90px 1fr; + row-gap: 22px; +} + +.card-pokemon__header { + display: grid; + grid-template-columns: 90px 1fr; + column-gap: 12px; + align-items: center; +} + +.card-pokemon__image { + max-width: 90px; +} + +.card-pokemon__title { + color: var(--color-dark); + font-size: 18px; + font-weight: 700; + line-height: normal; +} + +.card-pokemon__body { + list-style-type: none; + display: grid; + grid-template-columns: 1fr; + row-gap: 16px; +} + +.card-pokemon__text { + color: var(--color-dark); + font-size: 14px; + line-height: 21px; + font-weight: 400; +} + +.card-pokemon__text--bold { + color: var(--color-dark); + font-size: 14px; + line-height: 21px; + font-weight: 600; +} + +.card-pokemon__tag { + display: inline-block; + text-align: center; + min-width: 69px; + margin: 5px; + padding: 7px 9px; + color: #FFF; + background-color: var(--color-accent); + border-radius: 3px; +} + +.card-pokemon__tag--flying { + background-color: #FDB714; +} + +.card-pokemon__tag--fire { + background-color: #FC8B00; +} + +.card-pokemon__tag--psychic { + background-color: #FF87F3; +} + +.card-pokemon__tag--dragon { + background-color: #803078; +} + +.card-pokemon__tag--ice { + background-color: #A5CEDC; +} + +.card-pokemon__tag--water { + background-color: #00BAF7; +} + +.card-pokemon__tag--rock { + background-color: #7D7C7C; +} + +.card-pokemon__tag--ground { + background-color: #27561A; +} + +.card-pokemon__tag--electric { + background-color: #7B00FF; +} + +.card-pokemon__tag--poison { + background-color: #0F740F; +} + +.card-pokemon__tag--grass { + background-color: #738319; +} + +.card-pokemon__tag--ghost { + background-color: #B173B9; +} + +.card-pokemon__tag--normal { + background-color: #1B0A7C; +} + +.card-pokemon__tag--dark { + background-color: #414145; +} \ No newline at end of file diff --git a/docs/snischuk/styles/footer.css b/docs/snischuk/styles/footer.css new file mode 100644 index 00000000..0c98ea2e --- /dev/null +++ b/docs/snischuk/styles/footer.css @@ -0,0 +1,56 @@ +.footer { + min-width: 300px; + padding: 15px 0 20px; + background-color: var(--color-accent); +} + +.footer__container { + max-width: 1280px; + margin: 0 auto; + padding: 0 var(--padding-container); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 16px; +} + +.footer__soc-links { + list-style: none; + display: flex; + gap: 33px; +} + +.footer__soc-link { + transition: filter .3s ease-in-out; +} + +.footer__soc-link:hover { + filter: brightness(.9) +} + +.footer__text { + text-align: center; + color: var(--color-light); + font-size: 16px; + font-weight: 400; + line-height: 18px; +} + +@media (min-width: 769px) { + + .footer { + padding: 30px 0 40px; + } + + .footer__container { + gap: 32px; + } + + .footer__text { + text-align: center; + color: var(--color-light); + font-size: 22px; + line-height: 32px; + } +} \ No newline at end of file diff --git a/docs/snischuk/styles/header.css b/docs/snischuk/styles/header.css new file mode 100644 index 00000000..de9321da --- /dev/null +++ b/docs/snischuk/styles/header.css @@ -0,0 +1,63 @@ +.header { + min-width: 300px; + background-color: #333; + padding: 25px 0; +} + +.header__nav { + display: flex; + flex-wrap: wrap; + column-gap: 100px; + row-gap: 20px; + justify-content: space-between; + align-items: center; + max-width: 1280px; + margin: 0 auto; + padding: 0 var(--padding-container); +} + +.header__nav-list { + list-style-type: none; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + column-gap: 50px; + row-gap: 20px; +} + +.header__nav-link, +.header__nav-link--active { + color: var(--color-light); + font-size: 16px; + font-weight: 500; + text-decoration: none; + transition: color .3s ease-in-out; +} + +.header__nav-link--active { + padding: 7px 0; + position: relative; +} + +.header__nav-link:hover, +.header__nav-link--active:hover { + color: var(--color-accent); +} + +.header__nav-link--active::after { + content: ""; + position: absolute; + left: 0; + bottom: 0; + right: 0; + display: block; + width: 100%; + height: 1px; + background-color: var(--color-light); + transition: background-color .3s ease-in-out; +} + +.header__nav-link--active:hover::after { + background-color: var(--color-accent); +} \ No newline at end of file diff --git a/docs/snischuk/styles/login-success.css b/docs/snischuk/styles/login-success.css new file mode 100644 index 00000000..59a0844b --- /dev/null +++ b/docs/snischuk/styles/login-success.css @@ -0,0 +1,69 @@ +@import "./base.css"; +@import "./header.css"; +@import "./footer.css"; + +.success { + min-width: 300px; + padding: 0 var(--padding-container); + max-width: 605px; + margin: 20px auto; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 20px; +} + +.success__img { + display: block; + min-width: 200px; + border-radius: 50%; + border: 1px solid var(--color-accent); +} + +.success__title { + text-align: center; + color: var(--color-dark); + font-size: 32px; + line-height: 36px; + font-weight: 700; +} + +.success__text { + text-align: center; + font-size: 22px; + line-height: normal; + font-weight: 400; +} + +.success__link { + text-decoration: none; + text-align: center; + width: 100%; + padding: 27px; + border-radius: 6px; + background: var(--color-accent); + box-shadow: 0 4px 30px 0 rgba(38, 58, 67, .15); + color: #FFF; + font-size: 22px; + line-height: normal; + font-weight: 600; + transition: filter .3s ease-in-out; +} + +.success__link:hover { + filter: brightness(.9); +} + +@media (min-width: 769px) { + + .success { + margin: 40px auto; + row-gap: 40px; + } + + .success__title { + font-size: 42px; + line-height: 46px; + } +} \ No newline at end of file diff --git a/docs/snischuk/styles/login.css b/docs/snischuk/styles/login.css new file mode 100644 index 00000000..28ad51ba --- /dev/null +++ b/docs/snischuk/styles/login.css @@ -0,0 +1,154 @@ +@import "./base.css"; +@import "./header.css"; +@import "./footer.css"; + +.login { + min-width: 300px; + padding: 0 var(--padding-container); + max-width: 605px; + margin: 40px auto; +} + +.login__title { + text-align: center; + margin-bottom: 30px; + color: var(--color-dark); + font-family: Roboto; + font-size: 32px; + line-height: 36px; + font-weight: 700; +} + +.login__label { + margin-top: 60px; + display: block; + color: var(--color-dark); + font-family: Roboto; + font-size: 22px; + line-height: normal; + font-weight: 600; +} + +.login__field { + margin-top: 10px; + padding: 30px 20px; + display: block; + width: 100%; + border-radius: 6px; + border: 1px solid #A9A9A9; + background: #FFF; + color: var(--color-dark); + font-family: Roboto; + font-size: 14px; + line-height: 21px; + font-weight: 400; + border-bottom: 5px solid #A9A9A9; +} + +.login__field::placeholder { + color: #A9A9A9; + font-family: Roboto; + font-size: 14px; + line-height: 21px; + font-weight: 400; +} + +.login__field:hover, +.login__field:focus { + outline: none; + border-bottom: 5px solid var(--color-accent); +} + +.login__checkbox-input { + display: none; +} + +.login__checkbox-custom { + margin-top: 60px; + display: flex; + align-items: center; + color: var(--color-dark); + font-size: 14px; + line-height: 21px; +} + +.login__checkbox-custom::before { + content: ""; + margin-right: 12px; + padding: 3px; + display: inline-block; + width: 20px; + height: 20px; + border-radius: 6px; + border: 1px solid var(--color-accent); + background-color: #FFF; +} + +.login__checkbox-input:checked+.login__checkbox-custom::before { + background-image: url("../images/icon-check-login.svg"); + background-repeat: no-repeat; + background-size: contain; +} + +.login__btn { + margin-top: 60px; + cursor: pointer; + width: 100%; + padding: 27px; + border: none; + border-radius: 6px; + background: var(--color-accent); + box-shadow: 0 4px 30px 0 rgba(38, 58, 67, .15); + color: #FFF; + font-family: Roboto; + font-size: 22px; + line-height: normal; + font-weight: 600; + transition: filter .3s ease-in-out; +} + +.login__btn:hover { + filter: brightness(.9); +} + +.error { + position: absolute; + margin: 5px; + color: #F00; + font-size: 14px; + line-height: 21px; +} + +.error::before { + content: "x"; + margin-right: 5px; +} + +@media (min-width: 769px) { + + .login { + margin: 80px auto; + } + + .login__title { + margin-bottom: 60px; + font-size: 42px; + line-height: 46px; + } + + .login__label { + margin-top: 40px; + } + + .login__field { + margin-top: 22px; + } + + .login__checkbox-custom { + margin-top: 40px; + } + + .login__btn { + margin-top: 40px; + } +} \ No newline at end of file diff --git a/docs/snischuk/styles/pokemons.css b/docs/snischuk/styles/pokemons.css new file mode 100644 index 00000000..de51ba6a --- /dev/null +++ b/docs/snischuk/styles/pokemons.css @@ -0,0 +1,270 @@ +@import "./base.css"; +@import "./header.css"; +@import "./footer.css"; +@import "./card.css"; + +.filters { + min-width: 300px; + background-color: var(--color-dark); + padding: 12px 0; +} + +.filters__container { + max-width: 1280px; + padding: 0 var(--padding-container); + margin: 0 auto; + display: flex; + justify-content: space-between; + flex-wrap: wrap; + gap: 25px; + border: none; +} + +.filters__select-custom { + position: relative; + background-color: #333; + border-radius: 6px; +} + +.filters__select-custom-btn { + padding: 13px 20px; + cursor: pointer; + border: none; + background-color: transparent; + font-size: 16px; + color: var(--color-light); + transition: color .3s ease-in-out; +} + +.filters__select-custom-btn:hover { + color: var(--color-accent); +} + +.filters__select-list { + display: none; + position: absolute; + z-index: 1; + width: 100%; + margin: 0; + padding: 0; + list-style: none; +} + +.filters__select-list--active { + display: block; +} + +.filters__select-option { + padding: 13px 20px; + cursor: pointer; + background-color: #333; + font-size: 16px; + color: var(--color-light); + transition: color .3s ease-in-out; +} + +.filters__select-option:last-child { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; +} + +.filters__select-option:hover { + color: var(--color-accent); +} + +.filters__select-option--selected { + color: rgb(100, 200, 100); +} + +.filters__group { + display: flex; + align-items: center; + column-gap: 64px; + border: none; +} + +.filters__input { + display: none; +} + +.filters__custom { + display: flex; + align-items: center; + color: var(--color-light); + font-size: 14px; + line-height: 21px; + font-weight: 400; + position: relative; + padding-left: 40px; + transition: color .3s ease-in-out; +} + +.filters__custom:hover { + cursor: pointer; + color: var(--color-accent); +} + +.filters__custom::before, +.filters__custom::after { + content: ""; + padding: 3px; + display: inline-block; + width: 20px; + height: 20px; + border: 1px solid var(--color-light); + background-color: var(--color-dark); + position: absolute; + top: 50%; + transform: translateY(-50%); + left: 0; + transition: border .3s ease-in-out; +} + +.filters__custom:hover::before, +.filters__custom:hover::after { + border: 1px solid var(--color-accent); +} + +.filters__custom--radio::before { + border-radius: 50%; +} + +.filters__custom--radio::after { + opacity: 0; + border-radius: 50%; + background-image: url("../images/icon-radio-filter.svg"); + background-repeat: no-repeat; + background-size: contain; +} + +.filters__input:checked+.filters__custom--radio::after { + opacity: 1; +} + +.filters__search { + display: flex; + border: none; +} + +.filters__search-input { + padding-left: 46px; + background-color: var(--color-light); + background-image: url("../images/icon-search.svg"); + background-repeat: no-repeat; + background-position: 10px; + border: 2px solid transparent; + border-radius: 6px 0 0 6px; + font-family: Roboto; + color: var(--color-dark); + font-size: 14px; + line-height: 21px; + font-weight: 400; + transition: all .3s ease-in-out; +} + +.filters__search-input:hover { + border: 2px solid var(--color-accent); +} + +.filters__search-input::placeholder { + padding-right: 100px; + background-color: var(--color-light); + font-family: Roboto; + color: #A9A9A9; + font-size: 14px; + line-height: 21px; + font-weight: 400; +} + +.filters__search-input:focus { + outline: none; + border: 1px solid var(--color-accent); + transition: border .3s ease-in-out; +} + +.filters__btn-submit { + cursor: pointer; + padding: 13px 20px; + border: none; + border-radius: 0 6px 6px 0; + background: var(--color-accent); + color: var(--color-light); + font-family: Roboto; + font-size: 14px; + line-height: 21px; + font-weight: 400; + transition: filter .3s ease-in-out; +} + +.filters__btn-submit:hover { + filter: brightness(.9); +} + +.pokemons { + padding: 40px 0; +} + +.pokemons__container { + max-width: 1280px; + padding: 0 var(--padding-container); + margin: 0 auto; + display: grid; + grid-template-columns: 1fr; + row-gap: 40px; +} + +.pokemons__title { + color: var(--color-dark); + font-size: 40px; + line-height: normal; + font-weight: 700; +} + +.pokemons__cards { + list-style-type: none; + display: grid; + grid-template-columns: repeat(auto-fit, 275px); + gap: 25px; + justify-items: center +} + +.pokemons__card-item { + max-width: 275px; +} + +.pokemons__loader-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 10px; +} + +.pokemons__loader-text { + color: var(--color-dark); + font-size: 40px; +} + +.pokemons__loader-animation { + display: inline-block; + width: 80px; + height: 80px; + border: 3px solid rgba(255, 255, 255, .3); + border-radius: 50%; + border-top-color: var(--color-accent); + animation: spin 1s ease-in-out infinite; +} + +@keyframes spin { + + to { + transform: rotate(360deg); + } +} + +@media (min-width: 769px) { + + .pokemons__title { + font-size: 48px; + } +} \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/calculator.html b/homeworks/max.snischuk_snischuk/PokemonProject/calculator.html index d11649c4..65142ad5 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/calculator.html +++ b/homeworks/max.snischuk_snischuk/PokemonProject/calculator.html @@ -42,11 +42,56 @@

      Calculate pokemons

      - +

      + diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/images/about.jpeg b/homeworks/max.snischuk_snischuk/PokemonProject/images/about.jpeg new file mode 100644 index 00000000..ea741e9a Binary files /dev/null and b/homeworks/max.snischuk_snischuk/PokemonProject/images/about.jpeg differ diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/images/about.png b/homeworks/max.snischuk_snischuk/PokemonProject/images/about.png deleted file mode 100644 index 99dd48eb..00000000 Binary files a/homeworks/max.snischuk_snischuk/PokemonProject/images/about.png and /dev/null differ diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/index.html b/homeworks/max.snischuk_snischuk/PokemonProject/index.html index 1f31391d..0f547885 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/index.html +++ b/homeworks/max.snischuk_snischuk/PokemonProject/index.html @@ -32,7 +32,7 @@
      - pokemon + pokemon

      About me

      @@ -61,5 +61,50 @@

      About me

      + \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/login-success.html b/homeworks/max.snischuk_snischuk/PokemonProject/login-success.html index 39eaf471..ce01e8ee 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/login-success.html +++ b/homeworks/max.snischuk_snischuk/PokemonProject/login-success.html @@ -34,5 +34,50 @@

      Login successful!

      continue using the platform.

      Return to Home + \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/login.html b/homeworks/max.snischuk_snischuk/PokemonProject/login.html index 53f334bc..7e6c6c6d 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/login.html +++ b/homeworks/max.snischuk_snischuk/PokemonProject/login.html @@ -47,6 +47,51 @@

      Login page

      + \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/pokemons.html b/homeworks/max.snischuk_snischuk/PokemonProject/pokemons.html index 930e6630..84baf590 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/pokemons.html +++ b/homeworks/max.snischuk_snischuk/PokemonProject/pokemons.html @@ -67,6 +67,51 @@

      Study project "Pokemons"

      + \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/scripts/calculate.js b/homeworks/max.snischuk_snischuk/PokemonProject/scripts/calculate.js index 795707a0..29ed2965 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/scripts/calculate.js +++ b/homeworks/max.snischuk_snischuk/PokemonProject/scripts/calculate.js @@ -1,17 +1,3 @@ -/** - * Perform a mathematical operation on two numbers. Return result or error. - * @param firstValue {string} with first number - * @param secondValue {string} with second number - * @param operation {string} with operation symbol - * @returns {string} result of calculation pokemons or error message: - * - if firstValue or secondValue is not a number, return 'Enter a number' - * - if operation is not '+', '-', '*', '/', return 'Choose a valid operation' - * - if the result is more than 100, return 'Result is too big' - * - if the result is more than 1, - * return string of result and annotation in plural: 1 '+' 2 returns 3 pokemons - * - if the result is less than 1, - * return string of result and annotation in singular: 0.4 '+' 0.6 returns 1 pokemon - */ function calculate(firstValue, secondValue, operation) { let result; const firstNumber = Number(firstValue); diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/scripts/script.js b/homeworks/max.snischuk_snischuk/PokemonProject/scripts/script.js index d2856441..89cb84d7 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/scripts/script.js +++ b/homeworks/max.snischuk_snischuk/PokemonProject/scripts/script.js @@ -188,6 +188,8 @@ function firstOutputOperandHandler() { addElement(MATH_FIRST_OPERAND_ELEMENT, cardsList); } + + MATH_FIRST_OPERAND_ELEMENT.style.paddingBottom = '280px'; } function lastOutputOperandHandler() { @@ -226,20 +228,25 @@ function lastOutputOperandHandler() { addElement(MATH_LAST_OPERAND_ELEMENT, cardsList); remainingCards -= cardsInCurrentColumn; } + + MATH_LAST_OPERAND_ELEMENT.style.paddingBottom = '280px'; } } -CALCULATE_BUTTON_ELEMENT.addEventListener('click', () => { +function clickCalculateBtnHandler() { const measuredTime = measureTimeFn(renderMathExpressionElement); const dateCalculation = formatCustomDate(new Date()); CALCULATOR_TIME.innerHTML = `${dateCalculation} ${measuredTime}`; -}); +} -FIRST_VALUE_ELEMENT.addEventListener('input', () => { +function inputFirstValueHandler() { renderMathExpressionElement(); firstOutputOperandHandler(); const measuredTime = measureTimeFn(lastOutputOperandHandler); const dateCalculation = formatCustomDate(new Date()); CALCULATOR_TIME.innerHTML = `${dateCalculation} ${measuredTime}`; -}); +} + +CALCULATE_BUTTON_ELEMENT.addEventListener('click', clickCalculateBtnHandler); +FIRST_VALUE_ELEMENT.addEventListener('input', inputFirstValueHandler); diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/scripts/validateForm.js b/homeworks/max.snischuk_snischuk/PokemonProject/scripts/validateForm.js index 0aad775e..2b6aab95 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/scripts/validateForm.js +++ b/homeworks/max.snischuk_snischuk/PokemonProject/scripts/validateForm.js @@ -6,21 +6,12 @@ const RESULT_PAGE_PATH = './login-success.html'; const submitButton = document.getElementById(SUBMIT_BUTTON_ID); -/** - * Return input value by id. - * @param {string} elementId - * @return {string|boolean} input value - */ function getValueById(elementId) { const element = document.getElementById(elementId); const type = element.getAttribute('type'); return type === 'checkbox' ? element.checked : element.value; } -/** - * Add errors to errors container. - * @param {Object} inputData in format like: { [input_id]: error_text, ... } - */ function setErrors(inputId, errorMessage) { const inputElement = document.getElementById(inputId); const associatedLabels = inputElement.labels; @@ -33,17 +24,11 @@ function setErrors(inputId, errorMessage) { associatedLabels[0].insertAdjacentElement('afterend', errorElement); } -/** - * Delete all errors from errors container. - */ function deleteErrors() { const errorElement = document.querySelectorAll('[data-error]'); errorElement.forEach((element) => element.remove()); } -/** - * Goes to the page with the result. - */ function navigateToResultPage() { window.location.href = RESULT_PAGE_PATH; } @@ -69,9 +54,9 @@ function validateForm() { deleteErrors(); const errorMessages = { - [EMAIL_INPUT_ID]: 'Халепа... Перевірте формат пошти (приклад: email@localDomen.domen)', - [PASSWORD_INPUT_ID]: 'Упс... Довжина пароля має бути у діапазоні від 8 до 12 символів.', - [NOT_A_ROBOT_CHECKBOX_ID]: 'Ви шо, робот? Жмакніть на чекбокс!', + [EMAIL_INPUT_ID]: 'Please fill in the correct email (format example: email@localdomen.domen)', + [PASSWORD_INPUT_ID]: 'Oops... The password length should be in the range of 8 to 12 characters.', + [NOT_A_ROBOT_CHECKBOX_ID]: 'Are you a robot? Click on the checkbox!', }; const formValues = { diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/styles/about.css b/homeworks/max.snischuk_snischuk/PokemonProject/styles/about.css index 4d296ea1..e55896e0 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/styles/about.css +++ b/homeworks/max.snischuk_snischuk/PokemonProject/styles/about.css @@ -1,26 +1,20 @@ +@import "./base.css"; @import "./header.css"; - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: Roboto, sans-serif; -} +@import "./footer.css"; .about { - padding: 60px 0; + padding: 30px 0; } .about__container { + min-width: 300px; max-width: 1280px; - padding: 0 50px; + padding: 0 var(--padding-container); margin: 0 auto; display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); column-gap: 68px; + row-gap: 30px; } .about__image { @@ -32,28 +26,39 @@ body { .about__content { display: grid; grid-template-columns: 1fr; - row-gap: 32px; + row-gap: 16px; } .about__title { - color: #221F1F; + color: var(--color-dark); font-size: 48px; - line-height: 32px; + line-height: 52px; font-weight: 700; } .about__text { - color: #221F1F; + color: var(--color-dark); font-size: 22px; line-height: 32px; font-weight: 400; } .about__link { - color: #EF4934; + color: var(--color-accent); transition: color .3s ease-in-out; } .about__link:hover { color: #3354FA; +} + +@media (min-width: 769px) { + + .about { + padding: 60px 0; + } + + .about__content { + row-gap: 32px; + } } \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/styles/base.css b/homeworks/max.snischuk_snischuk/PokemonProject/styles/base.css new file mode 100644 index 00000000..f835c631 --- /dev/null +++ b/homeworks/max.snischuk_snischuk/PokemonProject/styles/base.css @@ -0,0 +1,35 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html, +body { + height: 100%; +} + +body { + font-family: Roboto, sans-serif; + display: flex; + flex-direction: column; +} + +main { + flex-grow: 1; +} + +:root { + --color-dark: #221F1F; + --color-light: #FFF; + --color-accent: #EF4934; + + --padding-container: 16px; +} + +@media (min-width: 769px) { + + :root { + --padding-container: 50px; + } +} \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/styles/calculator.css b/homeworks/max.snischuk_snischuk/PokemonProject/styles/calculator.css index d246065d..8e725441 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/styles/calculator.css +++ b/homeworks/max.snischuk_snischuk/PokemonProject/styles/calculator.css @@ -1,56 +1,53 @@ +@import "./base.css"; @import "./header.css"; +@import "./footer.css"; @import "./card.css"; -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: Roboto, sans-serif; -} - .calculator { - padding: 60px 0; + padding: 30px 0; } .calculator__container { + min-width: 300px; max-width: 1280px; - padding: 0 50px; + padding: 0 var(--padding-container); margin: 0 auto; display: flex; flex-direction: column; - gap: 60px; + gap: 30px; } - .calculator__title { text-align: center; - color: #221F1F; - font-size: 48px; - line-height: 32px; + color: var(--color-dark); + font-size: 42px; + line-height: 52px; font-weight: 700; } .calculator__field { display: flex; - column-gap: 10px; + flex-wrap: wrap; + gap: 10px; align-items: center; + justify-content: center; } .calculator__time { - color: #221F1F; + text-align: center; + color: var(--color-dark); font-size: 18px; line-height: 21px; } .calculator__input { - padding: 30px 20px; + max-width: 250px; + width: 100%; + padding: 20px; border-radius: 6px; - border: .6px solid #A9A9A9; - background: #FFF; - color: #221F1F; + border: 1px solid #A9A9A9; + background: var(--color-light); + color: var(--color-dark); font-family: Roboto; font-size: 14px; line-height: 21px; @@ -66,19 +63,22 @@ body { font-weight: 400; } +.calculator__input:hover, .calculator__input:focus { outline: none; - border-bottom: 1px solid #EF4934; + border-bottom: 1px solid var(--color-accent); } .calculator__select-math-sign { + max-width: 250px; + width: 100%; height: 100%; - padding: 27px 20px; + padding: 17px 20px; border-radius: 6px; - border: .6px solid #A9A9A9; - background: #FFF; + border: 1px solid #A9A9A9; + background: var(--color-light); font-family: Roboto; - color: #221F1F; + color: var(--color-dark); font-size: 22px; line-height: normal; font-weight: 600; @@ -88,17 +88,19 @@ body { .calculator__select-math-sign:hover, .calculator__select-math-sign:focus { outline: none; - border-bottom: 1px solid #EF4934; + border-bottom: 1px solid var(--color-accent); } .calculator__btn { + max-width: 250px; + width: 100%; cursor: pointer; - padding: 30px; + padding: 20px; border: none; border-radius: 6px; - background: #EF4934; + background: var(--color-accent); box-shadow: 0 4px 30px 0 rgba(38, 58, 67, .15); - color: #FFF; + color: var(--color-light); font-family: Roboto; font-size: 22px; line-height: normal; @@ -111,6 +113,7 @@ body { } .calculator__math-output { + text-align: center; font-size: 22px; line-height: 32px; font-weight: 400; @@ -118,10 +121,12 @@ body { .calculator__math-output-list { list-style: none; - display: grid; - grid-template-columns: repeat(4, auto) 1fr; + display: flex; + flex-wrap: wrap; + justify-content: center; align-items: center; gap: 30px; + flex-direction: column; } .calculator__column { @@ -131,14 +136,16 @@ body { } .calculator__math-output-item { - color: #F00; - font-size: 48px; - line-height: 32px; + color: var(--color-accent); + font-size: 36px; + line-height: 40px; font-weight: 700; column-gap: 20px; row-gap: 250px; display: flex; flex-wrap: wrap; + justify-content: center; + align-content: center; } .calculator__math-output-cards { @@ -146,10 +153,47 @@ body { } .calculator__math-output-card { - color: #F00; + color: var(--color-accent); font-size: 48px; line-height: 32px; font-weight: 700; width: 255px; height: 355px; +} + +@media (min-width: 768px) { + + .calculator { + padding: 60px 0; + } + + .calculator__container { + gap: 60px; + } + + .calculator__title { + font-size: 48px; + line-height: 48px; + } + + .calculator__input { + padding: 30px 20px; + } + + .calculator__select-math-sign { + padding: 27px 20px; + } + + .calculator__btn { + padding: 30px 20px; + } + + .calculator__math-output-list { + flex-direction: row; + } + + .calculator__math-output-item { + font-size: 48px; + line-height: 52px; + } } \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/styles/card.css b/homeworks/max.snischuk_snischuk/PokemonProject/styles/card.css index 0ea33a45..2cafd427 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/styles/card.css +++ b/homeworks/max.snischuk_snischuk/PokemonProject/styles/card.css @@ -1,4 +1,5 @@ .card-pokemon { + width: 100%; padding: 22px 12px; background-color: #ECECEC; border-radius: 12px; @@ -21,7 +22,7 @@ } .card-pokemon__title { - color: #221F1F; + color: var(--color-dark); font-size: 18px; font-weight: 700; line-height: normal; @@ -35,14 +36,14 @@ } .card-pokemon__text { - color: #221F1F; + color: var(--color-dark); font-size: 14px; line-height: 21px; font-weight: 400; } .card-pokemon__text--bold { - color: #221F1F; + color: var(--color-dark); font-size: 14px; line-height: 21px; font-weight: 600; @@ -58,7 +59,7 @@ line-height: 21px; font-weight: 400; color: #FFF; - background-color: #EF4934; + background-color: var(--color-accent); border: none; border-radius: 3px; transition: filter .3s ease-in-out; diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/styles/footer.css b/homeworks/max.snischuk_snischuk/PokemonProject/styles/footer.css new file mode 100644 index 00000000..0c98ea2e --- /dev/null +++ b/homeworks/max.snischuk_snischuk/PokemonProject/styles/footer.css @@ -0,0 +1,56 @@ +.footer { + min-width: 300px; + padding: 15px 0 20px; + background-color: var(--color-accent); +} + +.footer__container { + max-width: 1280px; + margin: 0 auto; + padding: 0 var(--padding-container); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 16px; +} + +.footer__soc-links { + list-style: none; + display: flex; + gap: 33px; +} + +.footer__soc-link { + transition: filter .3s ease-in-out; +} + +.footer__soc-link:hover { + filter: brightness(.9) +} + +.footer__text { + text-align: center; + color: var(--color-light); + font-size: 16px; + font-weight: 400; + line-height: 18px; +} + +@media (min-width: 769px) { + + .footer { + padding: 30px 0 40px; + } + + .footer__container { + gap: 32px; + } + + .footer__text { + text-align: center; + color: var(--color-light); + font-size: 22px; + line-height: 32px; + } +} \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/styles/header.css b/homeworks/max.snischuk_snischuk/PokemonProject/styles/header.css index cb5eefb0..de9321da 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/styles/header.css +++ b/homeworks/max.snischuk_snischuk/PokemonProject/styles/header.css @@ -1,32 +1,34 @@ .header { + min-width: 300px; background-color: #333; padding: 25px 0; } .header__nav { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); - gap: 15px; + display: flex; + flex-wrap: wrap; + column-gap: 100px; + row-gap: 20px; + justify-content: space-between; + align-items: center; max-width: 1280px; margin: 0 auto; - padding: 0 50px; - justify-content: space-between; + padding: 0 var(--padding-container); } .header__nav-list { - justify-self: end; list-style-type: none; - display: grid; - grid-auto-flow: column; - grid-auto-columns: 1fr; - column-gap: 50px; - justify-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; align-items: center; + column-gap: 50px; + row-gap: 20px; } .header__nav-link, .header__nav-link--active { - color: #FFF; + color: var(--color-light); font-size: 16px; font-weight: 500; text-decoration: none; @@ -40,7 +42,7 @@ .header__nav-link:hover, .header__nav-link--active:hover { - color: #EF4934; + color: var(--color-accent); } .header__nav-link--active::after { @@ -52,10 +54,10 @@ display: block; width: 100%; height: 1px; - background-color: #FFF; + background-color: var(--color-light); transition: background-color .3s ease-in-out; } .header__nav-link--active:hover::after { - background-color: #EF4934; + background-color: var(--color-accent); } \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/styles/login-success.css b/homeworks/max.snischuk_snischuk/PokemonProject/styles/login-success.css index 6e1c98dd..59a0844b 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/styles/login-success.css +++ b/homeworks/max.snischuk_snischuk/PokemonProject/styles/login-success.css @@ -1,37 +1,31 @@ +@import "./base.css"; @import "./header.css"; - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: Roboto, sans-serif; -} +@import "./footer.css"; .success { - padding: 0 15px; + min-width: 300px; + padding: 0 var(--padding-container); max-width: 605px; - margin: 40px auto; + margin: 20px auto; display: flex; flex-direction: column; justify-content: center; align-items: center; - row-gap: 40px; + row-gap: 20px; } .success__img { display: block; min-width: 200px; border-radius: 50%; - border: 1px solid #EF4934; + border: 1px solid var(--color-accent); } .success__title { - color: #221F1F; - font-size: 48px; - line-height: 32px; + text-align: center; + color: var(--color-dark); + font-size: 32px; + line-height: 36px; font-weight: 700; } @@ -48,7 +42,7 @@ body { width: 100%; padding: 27px; border-radius: 6px; - background: #EF4934; + background: var(--color-accent); box-shadow: 0 4px 30px 0 rgba(38, 58, 67, .15); color: #FFF; font-size: 22px; @@ -59,4 +53,17 @@ body { .success__link:hover { filter: brightness(.9); +} + +@media (min-width: 769px) { + + .success { + margin: 40px auto; + row-gap: 40px; + } + + .success__title { + font-size: 42px; + line-height: 46px; + } } \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/styles/login.css b/homeworks/max.snischuk_snischuk/PokemonProject/styles/login.css index 6eb8b551..28ad51ba 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/styles/login.css +++ b/homeworks/max.snischuk_snischuk/PokemonProject/styles/login.css @@ -1,35 +1,28 @@ +@import "./base.css"; @import "./header.css"; - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: Roboto, sans-serif; -} +@import "./footer.css"; .login { - padding: 0 15px; + min-width: 300px; + padding: 0 var(--padding-container); max-width: 605px; - margin: 80px auto; + margin: 40px auto; } .login__title { text-align: center; - margin-bottom: 60px; - color: #221F1F; + margin-bottom: 30px; + color: var(--color-dark); font-family: Roboto; - font-size: 48px; - line-height: 32px; + font-size: 32px; + line-height: 36px; font-weight: 700; } .login__label { + margin-top: 60px; display: block; - margin-top: 40px; - color: #221F1F; + color: var(--color-dark); font-family: Roboto; font-size: 22px; line-height: normal; @@ -37,18 +30,19 @@ body { } .login__field { - margin-top: 22px; + margin-top: 10px; padding: 30px 20px; display: block; width: 100%; border-radius: 6px; - border: .6px solid #A9A9A9; + border: 1px solid #A9A9A9; background: #FFF; - color: #221F1F; + color: var(--color-dark); font-family: Roboto; font-size: 14px; line-height: 21px; font-weight: 400; + border-bottom: 5px solid #A9A9A9; } .login__field::placeholder { @@ -59,9 +53,10 @@ body { font-weight: 400; } +.login__field:hover, .login__field:focus { outline: none; - border-bottom: 5px solid #EF4934; + border-bottom: 5px solid var(--color-accent); } .login__checkbox-input { @@ -69,10 +64,10 @@ body { } .login__checkbox-custom { + margin-top: 60px; display: flex; align-items: center; - margin-top: 40px; - color: #221F1F; + color: var(--color-dark); font-size: 14px; line-height: 21px; } @@ -85,7 +80,7 @@ body { width: 20px; height: 20px; border-radius: 6px; - border: 1px solid #EF4934; + border: 1px solid var(--color-accent); background-color: #FFF; } @@ -96,13 +91,13 @@ body { } .login__btn { - margin-top: 40px; + margin-top: 60px; cursor: pointer; width: 100%; padding: 27px; border: none; border-radius: 6px; - background: #EF4934; + background: var(--color-accent); box-shadow: 0 4px 30px 0 rgba(38, 58, 67, .15); color: #FFF; font-family: Roboto; @@ -117,8 +112,43 @@ body { } .error { + position: absolute; margin: 5px; color: #F00; font-size: 14px; line-height: 21px; +} + +.error::before { + content: "x"; + margin-right: 5px; +} + +@media (min-width: 769px) { + + .login { + margin: 80px auto; + } + + .login__title { + margin-bottom: 60px; + font-size: 42px; + line-height: 46px; + } + + .login__label { + margin-top: 40px; + } + + .login__field { + margin-top: 22px; + } + + .login__checkbox-custom { + margin-top: 40px; + } + + .login__btn { + margin-top: 40px; + } } \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/styles/pokemons.css b/homeworks/max.snischuk_snischuk/PokemonProject/styles/pokemons.css index 763ae9d0..de51ba6a 100644 --- a/homeworks/max.snischuk_snischuk/PokemonProject/styles/pokemons.css +++ b/homeworks/max.snischuk_snischuk/PokemonProject/styles/pokemons.css @@ -1,30 +1,22 @@ -@import "./variables.css"; +@import "./base.css"; @import "./header.css"; +@import "./footer.css"; @import "./card.css"; -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: Roboto, sans-serif; -} - .filters { + min-width: 300px; background-color: var(--color-dark); padding: 12px 0; } .filters__container { max-width: 1280px; - padding: 0 50px; + padding: 0 var(--padding-container); margin: 0 auto; display: flex; justify-content: space-between; flex-wrap: wrap; - gap: 15px; + gap: 25px; border: none; } @@ -214,7 +206,7 @@ body { .pokemons__container { max-width: 1280px; - padding: 0 50px; + padding: 0 var(--padding-container); margin: 0 auto; display: grid; grid-template-columns: 1fr; @@ -223,7 +215,7 @@ body { .pokemons__title { color: var(--color-dark); - font-size: 48px; + font-size: 40px; line-height: normal; font-weight: 700; } @@ -233,6 +225,7 @@ body { display: grid; grid-template-columns: repeat(auto-fit, 275px); gap: 25px; + justify-items: center } .pokemons__card-item { @@ -267,4 +260,11 @@ body { to { transform: rotate(360deg); } +} + +@media (min-width: 769px) { + + .pokemons__title { + font-size: 48px; + } } \ No newline at end of file diff --git a/homeworks/max.snischuk_snischuk/PokemonProject/styles/variables.css b/homeworks/max.snischuk_snischuk/PokemonProject/styles/variables.css deleted file mode 100644 index e28a0e99..00000000 --- a/homeworks/max.snischuk_snischuk/PokemonProject/styles/variables.css +++ /dev/null @@ -1,5 +0,0 @@ -:root { - --color-dark: #221F1F; - --color-light: #FFF; - --color-accent: #EF4934; -} \ No newline at end of file