Skip to content

Commit

Permalink
Merge pull request #16 from PandaST47/master
Browse files Browse the repository at this point in the history
  • Loading branch information
keksobot authored Jan 4, 2025
2 parents ac34137 + 32ecfee commit 1003df0
Show file tree
Hide file tree
Showing 23 changed files with 116 additions and 5,618 deletions.
11 changes: 6 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,12 @@ <h2 class="success__title">Изображение успешно загруже
</div>
</section>
</template>
<script type = 'module' src="js/main.js"></script>
<script src="sha256-Pristine-d2ee511/dist/pristine.js" type="text/javascript"></script>
<!-- Стили noUiSlider -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/15.7.1/nouislider.min.css">
<!-- Скрипт pristine -->
<script src="vendor/pristine/pristine.min.js" type="text/javascript"></script>
<!-- Скрипт noUiSlider -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/15.7.1/nouislider.min.js"></script>
<script src="vendor/nouislider/nouislider.js"></script>
<link rel="stylesheet" href="vendor/nouislider/nouislider.css">
<!-- Скрипты -->
<script src="js/main.js" type="module"></script>
</body>
</html>
40 changes: 24 additions & 16 deletions js/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,34 @@ function applyFilter(photos, filter) {
export function initFilters(photos, renderThumbnails) {
photoFilters.classList.remove('img-filters--inactive');

let selectedFilter = null;

const applyDebouncedFilter = debounce(() => {
if (selectedFilter) {
clearThumbnails();
const filteredPhotos = applyFilter(photos, selectedFilter);
renderThumbnails(filteredPhotos);
}
}, 500);

filterButtons.forEach((button) => {
button.addEventListener(
'click',
debounce((evt) => {
// Удаляем класс активности у всех кнопок
filterButtons.forEach((btn) => btn.classList.remove('img-filters__button--active'));

// Добавляем класс активности нажатой кнопке
evt.target.classList.add('img-filters__button--active');

clearThumbnails();

// Применяем выбранный фильтр и отрисовываем миниатюры
const filteredPhotos = applyFilter(photos, evt.target.id);
renderThumbnails(filteredPhotos);
}, 500)
);
button.addEventListener('click', (evt) => {
// Удаляем класс активности у всех кнопок
filterButtons.forEach((btn) => btn.classList.remove('img-filters__button--active'));

// Устанавливаем класс активности для текущей кнопки
evt.target.classList.add('img-filters__button--active');

// Сохраняем выбранный фильтр
selectedFilter = evt.target.id;

// Запускаем отложенное применение фильтра
applyDebouncedFilter();
});
});
}


function clearThumbnails() {
const pictures = document.querySelectorAll('.picture');
pictures.forEach((picture) => picture.remove());
Expand Down
43 changes: 25 additions & 18 deletions js/form-api.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
/* Импорт для функционала с загрузкой картинок. Решил не убирать раз создал, но закомментил
import { photos } from './photos.js';
import { renderThumbnails } from './thumbnails.js';
// import { renderThumbnails } from './thumbnails.js';
import { pristine, currentEffect, resetForm } from './form.js';
*/
import { pristine, resetForm } from './form.js';

export const uploadForm = document.querySelector('.img-upload__form');
export const fileInput = uploadForm.querySelector('.img-upload__input');
Expand All @@ -27,7 +24,6 @@ uploadForm.addEventListener('submit', (evt) => {
})
.then((response) => {
if (response.ok) {
/*
// Добавляем новую фотографию с эффектом
const newPhoto = {
id: photos.length + 1,
Expand All @@ -37,10 +33,9 @@ uploadForm.addEventListener('submit', (evt) => {
comments: [],
effect: currentEffect // Сохраняем текущий эффект
};
photos.push(newPhoto); // Добавляем фото в массив
renderThumbnails([newPhoto]); // Добавляем миниатюру
*/
// renderThumbnails([newPhoto]); // Добавляем миниатюру

showSuccessMessage(); // Показ успешного сообщения
resetForm();
} else {
Expand Down Expand Up @@ -68,19 +63,25 @@ function showSuccessMessage() {

function closeSuccess() {
successOverlay.remove();
document.removeEventListener('keydown', onKeydownSuccess);
document.removeEventListener('click', onClickOutsideSuccess);
}

closeButton.addEventListener('click', closeSuccess);
document.addEventListener('keydown', (evt) => {
function onKeydownSuccess(evt) {
if (evt.key === 'Escape') {
closeSuccess();
}
});
document.addEventListener('click', (evt) => {
}

function onClickOutsideSuccess(evt) {
if (evt.target === successOverlay) {
closeSuccess();
}
});
}

closeButton.addEventListener('click', closeSuccess);
document.addEventListener('keydown', onKeydownSuccess);
document.addEventListener('click', onClickOutsideSuccess);
}

function showErrorMessage() {
Expand All @@ -93,17 +94,23 @@ function showErrorMessage() {

function closeError() {
errorOverlay.remove();
document.removeEventListener('keydown', onKeydownError);
document.removeEventListener('click', onClickOutsideError);
}

closeButton.addEventListener('click', closeError);
document.addEventListener('keydown', (evt) => {
function onKeydownError(evt) {
if (evt.key === 'Escape') {
closeError();
}
});
document.addEventListener('click', (evt) => {
}

function onClickOutsideError(evt) {
if (evt.target === errorOverlay) {
closeError();
}
});
}

closeButton.addEventListener('click', closeError);
document.addEventListener('keydown', onKeydownError);
document.addEventListener('click', onClickOutsideError);
}
120 changes: 55 additions & 65 deletions js/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const scaleValue = uploadOverlay.querySelector('.scale__control--value');

export let currentEffect = 'none';
const effectRadios = document.querySelectorAll('input[name="effect"]');
const effectLevelSliderContainer = document.querySelector('.effect-level'); // Контейнер слайдера
const effectLevelSlider = document.querySelector('.effect-level__slider');
const effectLevelValue = document.querySelector('.effect-level__value');

Expand All @@ -28,17 +29,15 @@ function validateHashtags(value) {
const hashtags = value.trim().toLowerCase().split(/\s+/);
const hashtagPattern = /^#[a-zа-яё0-9]{1,19}$/;

if (hashtags.length > 5) {
return false; // Максимум 5 хэштегов
}
return hashtags.every((tag) => hashtagPattern.test(tag)) &&
new Set(hashtags).size === hashtags.length; // Проверка на уникальность
return hashtags.length <= 5 &&
hashtags.every((tag) => hashtagPattern.test(tag)) &&
new Set(hashtags).size === hashtags.length; // Уникальность
}

pristine.addValidator(
hashtagInput,
validateHashtags,
'Хэш-теги должны начинаться с #, быть не длиннее 20 символов и без повторений. Максимум 5 хэш-тегов.'
'Хэш-теги должны начинаться с #, быть не длиннее 20 символов и без повторений. Максимум 5 хэштегов.'
);

// Валидация комментария
Expand All @@ -52,42 +51,39 @@ pristine.addValidator(
'Комментарий не должен превышать 140 символов.'
);

const previewImage = uploadOverlay.querySelector('.img-upload__preview img'); // Пример выбора превью
const previewImage = uploadOverlay.querySelector('.img-upload__preview img');
fileInput.addEventListener('change', () => {
const file = fileInput.files[0];
if (file) {
const imageUrl = URL.createObjectURL(file); // Создаём временный URL для изображения
previewImage.src = imageUrl; // Устанавливаем путь для previewImage
uploadOverlay.classList.remove('hidden'); // Показываем форму
document.body.classList.add('modal-open'); // Добавляем класс modal-open
const imageUrl = URL.createObjectURL(file);
previewImage.src = imageUrl;
uploadOverlay.classList.remove('hidden');
document.body.classList.add('modal-open');

// Установка начального состояния
currentEffect = 'none';
updateSlider(currentEffect); // Сбрасываем слайдер в состояние для "оригинал"
effectLevelValue.value = ''; // Очищаем значение эффекта
previewImage.style.filter = ''; // Сбрасываем фильтры
pristine.reset(); // Сбрасываем ошибки валидации
applyScale(currentScale); // Применяем начальный масштаб
updateSlider(currentEffect);
effectLevelValue.value = '';
previewImage.style.filter = '';
pristine.reset();
applyScale(currentScale);
}
});

// --------- Функция для применения масштаба ---------

export function applyScale(scale) {
scaleValue.value = `${scale}%`; // Исправлено: корректный синтаксис
scaleValue.value = `${scale}%`;
const scaleFactor = scale / 100;
previewImage.style.transform = `scale(${scaleFactor})`; // Исправлено: корректный синтаксис
previewImage.style.transform = `scale(${scaleFactor})`;
}


scaleSmaller.addEventListener('click', () => {
if (currentScale > 25) {
currentScale -= 25;
applyScale(currentScale);
}
});


scaleBigger.addEventListener('click', () => {
if (currentScale < 100) {
currentScale += 25;
Expand All @@ -96,7 +92,6 @@ scaleBigger.addEventListener('click', () => {
});

// --------- Слайдер и эффекты ---------

noUiSlider.create(effectLevelSlider, {
range: {
min: 0,
Expand All @@ -107,83 +102,78 @@ noUiSlider.create(effectLevelSlider, {
connect: 'lower',
});

effectLevelSliderContainer.style.display = 'none'; // Скрываем слайдер по умолчанию

function applyEffect(effect, value) {
const imageElement = document.querySelector('.img-upload__preview img');
imageElement.className = ''; // Сбрасываем предыдущий класс эффекта
previewImage.style.filter = ''; // Сбрасываем фильтр

if (effect !== 'none') {
imageElement.classList.add(`effects__preview--${effect}`); // Исправлено: использование шаблонной строки
const filterValue = value / 100; // Пример нормализации значения слайдера
switch (effect) {
case 'chrome':
previewImage.style.filter = `grayscale(${filterValue})`; // Исправлено
break;
case 'sepia':
previewImage.style.filter = `sepia(${filterValue})`; // Исправлено
break;
case 'marvin':
previewImage.style.filter = `invert(${filterValue * 100}%)`; // Исправлено
break;
case 'phobos':
previewImage.style.filter = `blur(${filterValue * 3}px)`; // Исправлено
break;
case 'heat':
previewImage.style.filter = `brightness(${1 + filterValue * 2})`; // Исправлено
break;
}
const filterValue = value / 100;
switch (effect) {
case 'chrome':
previewImage.style.filter = `grayscale(${filterValue})`;
break;
case 'sepia':
previewImage.style.filter = `sepia(${filterValue})`;
break;
case 'marvin':
previewImage.style.filter = `invert(${value}%)`;
break;
case 'phobos':
previewImage.style.filter = `blur(${(value * 3) / 100}px)`;
break;
case 'heat':
previewImage.style.filter = `brightness(${1 + (filterValue * 2)})`;
break;
case 'none':
default:
previewImage.style.filter = '';
break;
}
}

// Обновление слайдера при переключении фильтра
function updateSlider(effect) {
if (effect === 'none') {
effectLevelSlider.classList.add('hidden');
effectLevelValue.value = 0; // Устанавливаем значение эффекта в 0
if (effectLevelSlider.noUiSlider) {
effectLevelSlider.noUiSlider.set(0); // Перемещаем ползунок в 0
}
effectLevelSliderContainer.style.display = 'none';
effectLevelValue.value = '';
previewImage.style.filter = '';
} else {
effectLevelSlider.classList.remove('hidden');
effectLevelSliderContainer.style.display = 'block';
effectLevelSlider.noUiSlider.updateOptions({
range: { min: 0, max: 100 },
start: 100, // Сброс значения слайдера в 100
start: 100,
});
effectLevelValue.value = 100; // Устанавливаем начальное значение для эффекта
effectLevelValue.value = 100;
}
}

// Обработчик переключения фильтров
effectRadios.forEach((radio) => {
radio.addEventListener('change', (evt) => {
currentEffect = evt.target.value;
updateSlider(currentEffect); // Сбрасываем слайдер в 0 при смене эффекта
updateSlider(currentEffect);
applyEffect(currentEffect, effectLevelSlider.noUiSlider.get());
});
});

// Обновление эффекта при движении слайдера
effectLevelSlider.noUiSlider.on('update', (values) => {
const value = Math.round(values[0]);
effectLevelValue.value = value; // Записываем значение в скрытое поле
applyEffect(currentEffect, value); // Применяем эффект
effectLevelValue.value = value;
applyEffect(currentEffect, value);
});

// --------- Закрытие формы ---------

export function resetForm() {
uploadForm.reset();
pristine.reset();
uploadOverlay.classList.add('hidden');
document.body.classList.remove('modal-open');
fileInput.value = ''; // Очищаем контрол загрузки файла
currentScale = 100; // Сбрасываем масштаб
applyScale(currentScale); // Применяем сброс масштаба
previewImage.className = ''; // Удаляем классы эффектов
currentEffect = 'none'; // Устанавливаем эффект в 'оригинал'
updateSlider(currentEffect); // Сбрасываем слайдер
previewImage.style.filter = ''; // Удаляем все фильтры
fileInput.value = '';
currentScale = 100;
applyScale(currentScale);
previewImage.className = '';
currentEffect = 'none';
updateSlider(currentEffect);
previewImage.style.filter = '';
}

// Закрытие формы по Esc
Expand Down
13 changes: 6 additions & 7 deletions js/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ export function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

export function debounce(callback, delay) {
let timeout;
return (...rest) => {
clearTimeout(timeout);
timeout = setTimeout(() => callback.apply(this, rest), delay);
export const debounce = (callback, timeoutDelay = 500) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => callback(...args), timeoutDelay);
};
}

};
Loading

0 comments on commit 1003df0

Please sign in to comment.