diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..330aaca --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,14 @@ +# Используем базовый образ Node.js +FROM node:latest + +# Устанавливаем рабочую директорию в контейнере +WORKDIR /app + +# Копируем все файлы проекта в контейнер +COPY . . + +# Устанавливаем зависимости +RUN npm install + +# Определяем команду, которая будет выполняться при каждом запуске контейнера +CMD npm run build && chown -R 1000:1000 ./dist diff --git a/frontend/docker-compose.yml b/frontend/docker-compose.yml new file mode 100644 index 0000000..20c3a64 --- /dev/null +++ b/frontend/docker-compose.yml @@ -0,0 +1,6 @@ +version: '3' +services: + app: + build: . + volumes: + - ./dist:/app/dist diff --git a/frontend/postcss.config.cjs b/frontend/postcss.config.cjs new file mode 100644 index 0000000..a47ef4f --- /dev/null +++ b/frontend/postcss.config.cjs @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + autoprefixer: {}, + }, +}; diff --git a/frontend/public/images/video-preview@2x.png b/frontend/public/images/video-preview@2x.png new file mode 100644 index 0000000..8797527 Binary files /dev/null and b/frontend/public/images/video-preview@2x.png differ diff --git a/frontend/src/main.js b/frontend/src/main.js new file mode 100644 index 0000000..ec0f305 --- /dev/null +++ b/frontend/src/main.js @@ -0,0 +1,76 @@ +import 'reset-css'; +import './global.css'; +import './scripts/header.js'; +import './styles/layout/container.css'; +import './styles/layout/footer.css'; +import './styles/layout/header/header.css'; + +import './styles/layout/container.css'; +import './styles/layout/footer.css'; + +import './styles/components/advert-item.css'; +import './styles/components/article-item.css'; +import './styles/components/article-single.css'; +import './styles/components/contacts.css'; +import './styles/components/event-item.css'; +import './styles/components/interview-item.css'; +import './styles/components/partner-item.css'; +import './styles/components/single-partner-item.css'; +import './styles/components/suggestion-item.css'; + +import './scripts/calendar.js'; +import './scripts/menu-vertical.js'; +import './scripts/modal.js'; +import './scripts/scroll-to-top.js'; +import './scripts/search-form.js'; +import './scripts/select.js'; +import './scripts/subscription-form.js'; +import './styles/components/about.css'; +import './styles/components/banner.css'; +import './styles/components/breadcrumbs.css'; +import './styles/components/button.css'; +import './styles/components/calendar.css'; +import './styles/components/checkbox.css'; +import './styles/components/error-page.css'; +import './styles/components/event-item.css'; +import './styles/components/fonts.css'; +import './styles/components/hero.css'; +import './styles/components/input.css'; +import './styles/components/menu-vertical.css'; +import './styles/components/menu.css'; +import './styles/components/modal.css'; +import './styles/components/most-read.css'; +import './styles/components/nav.css'; +import './styles/components/pagination.css'; +import './styles/components/search-form.css'; +import './styles/components/section-title.css'; +import './styles/components/select.css'; +import './styles/components/shared.css'; +import './styles/components/socials.css'; +import './styles/components/subscribe-form.css'; +import './styles/components/subscription-form.css'; +import './styles/components/tag.css'; +import './styles/components/to-top.css'; +import './styles/components/upcoming-events.css'; + +import { initCalendar } from './scripts/calendar.js'; +import { initMenuVertical } from './scripts/menu-vertical.js'; +import { initModal } from './scripts/modal.js'; +import { initScrollToTop } from './scripts/scroll-to-top.js'; + +import { initHeader } from './scripts/header.js'; +import { initSearchForm } from './scripts/search-form.js'; +import { initSelect } from './scripts/select.js'; +import { initSubscriptionForm } from './scripts/subscription-form.js'; +import './styles/pages/main.css'; + +document.addEventListener('DOMContentLoaded', function () { + initCalendar(); + initMenuVertical(); + initModal(); + initScrollToTop(); + initSearchForm(); + initSelect(); + initSubscriptionForm(); + initHeader(); +}); diff --git a/frontend/src/scripts/header.js b/frontend/src/scripts/header.js new file mode 100644 index 0000000..ef2deda --- /dev/null +++ b/frontend/src/scripts/header.js @@ -0,0 +1,11 @@ +export const initHeader = () => { + const headerBurger = document.querySelector('.header__burger'); + const mobileHeader = document.querySelector('.header-mobile'); + + if (headerBurger && mobileHeader) { + headerBurger.addEventListener('click', () => { + mobileHeader.classList.toggle('is-active'); + headerBurger.classList.toggle('is-active'); + }); + } +}; diff --git a/frontend/src/scripts/menu-vertical.js b/frontend/src/scripts/menu-vertical.js new file mode 100644 index 0000000..c383798 --- /dev/null +++ b/frontend/src/scripts/menu-vertical.js @@ -0,0 +1,14 @@ +export const initMenuVertical = () => { + const menuVerticalHead = document.querySelector( + '.mobile .menu-vertical__head' + ); + const menuVerticalInner = document.querySelector( + '.mobile .menu-vertical__inner' + ); + if (menuVerticalHead && menuVerticalInner) { + menuVerticalHead.addEventListener('click', () => { + menuVerticalHead.classList.toggle('is-active'); + menuVerticalInner.classList.toggle('is-active'); + }); + } +}; diff --git a/frontend/src/scripts/modal.js b/frontend/src/scripts/modal.js new file mode 100644 index 0000000..0707cb7 --- /dev/null +++ b/frontend/src/scripts/modal.js @@ -0,0 +1,13 @@ +export const initModal = () => { + const modalCloses = document.querySelectorAll('.modal__close'); + + if (modalCloses.length) { + modalCloses.forEach(function (modalClose) { + modalClose.addEventListener('click', function (event) { + event.preventDefault(); + const modal = this.closest('.modal-overlay'); + modal.style.display = 'none'; + }); + }); + } +}; diff --git a/frontend/src/scripts/search-form.js b/frontend/src/scripts/search-form.js new file mode 100644 index 0000000..7d39048 --- /dev/null +++ b/frontend/src/scripts/search-form.js @@ -0,0 +1,10 @@ +export const initSearchForm = () => { + const searchFormInput = document.querySelector('.search-form__input'); + const searchFormClearButton = document.querySelector('.search-form__clear'); + + if (searchFormInput && searchFormClearButton) { + searchFormClearButton.addEventListener('click', () => { + searchFormInput.value = ''; + }); + } +}; diff --git a/frontend/src/scripts/select.js b/frontend/src/scripts/select.js new file mode 100644 index 0000000..4869ded --- /dev/null +++ b/frontend/src/scripts/select.js @@ -0,0 +1,24 @@ +import SlimSelect from 'slim-select'; +import 'slim-select/styles'; + +export const initSelect = () => { + const settings = { + showSearch: false, + hideSelected: true, + }; + + new SlimSelect({ + select: '#selectSort', + settings, + }); + + new SlimSelect({ + select: '#selectDate', + settings, + }); + + new SlimSelect({ + select: '#selectCategory', + settings, + }); +};