Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e2fd85324 | |||
| d723610f63 | |||
| ecca78f2e6 |
26
.eslintrc.js
26
.eslintrc.js
@@ -1,32 +1,20 @@
|
||||
export default {
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
'plugin:prettier/recommended'
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
},
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module'
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['react', 'react-hooks', 'prettier'],
|
||||
rules: {
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
'react/prop-types': 'off',
|
||||
'prettier/prettier': 'warn',
|
||||
'no-unused-vars': 'warn'
|
||||
'prettier/prettier': 'error',
|
||||
'no-unused-vars': 'warn',
|
||||
'no-console': 'warn',
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect'
|
||||
}
|
||||
}
|
||||
};
|
||||
136
about.html
Normal file
136
about.html
Normal file
@@ -0,0 +1,136 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>О фильме - Online Cinema Theater</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигационная панель -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark-custom fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="index.html">
|
||||
<img src="resources/logo.webp" alt="Online Cinema Theater Logo" width="50" height="50" class="me-2">
|
||||
<span>Online Cinema Theater</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.html">Главная</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="catalog.html">Каталог</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="reviews.html">Рецензии</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
|
||||
Что глянуть?
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-dark">
|
||||
<li><a class="dropdown-item" href="films.html">Фильмы</a></li>
|
||||
<li><a class="dropdown-item" href="seriales.html">Сериалы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<main class="container py-5 mt-5">
|
||||
<section class="movie-details">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="card bg-dark">
|
||||
<img src="resources/movies/gruz.jpeg" class="card-img-top" alt="Movie Poster">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card bg-dark">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title text-white mb-4">Груз 200</h1>
|
||||
<table class="table table-dark table-hover">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Продолжительность</th>
|
||||
<td class="text-light">1 час 50 минут</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Год выпуска</th>
|
||||
<td class="text-light">2007</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Страна</th>
|
||||
<td class="text-light">Россия</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Режиссер</th>
|
||||
<td class="text-light">Алексей Балабанов</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Жанр</th>
|
||||
<td class="text-light">триллер, драма, криминал</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h5 class="text-white mt-4">Описание:</h5>
|
||||
<p class="text-light">
|
||||
Груз 200 - это история о двух братьях, которые вместе с другими людьми отправляются в грузовике на
|
||||
поиски золота в Африке. Однако путь к цели оказывается опасным и сложным, и братья сталкиваются
|
||||
с различными препятствиями, в том числе с коррупцией и жестокостью.
|
||||
</p>
|
||||
<div class="ratio ratio-16x9 mt-4">
|
||||
<iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ?si=iaZ0q33EJFBzeIZ_?autoplay=1"
|
||||
title="YouTube video player"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Футер -->
|
||||
<footer class="bg-dark-custom text-light py-4">
|
||||
<div class="container">
|
||||
<div class="row gy-4">
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Контактная информация</h5>
|
||||
<p class="mb-1">Телефон: +7 (123) 456-78-90</p>
|
||||
<p class="mb-1">Email: info@cinema.com</p>
|
||||
<p>Адрес: ул. Примерная, 123, Москва, Россия</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Мы в соцсетях</h5>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="#" class="text-light"><i class="bi bi-telegram fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-whatsapp fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-vk fs-4"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Время работы</h5>
|
||||
<p class="mb-1">Понедельник - Пятница: 10:00 - 22:00</p>
|
||||
<p>Суббота - Воскресенье: 12:00 - 24:00</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col text-center">
|
||||
<p class="mb-0">© 2022 Online Cinema Theater. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
141
add-movie.html
Normal file
141
add-movie.html
Normal file
@@ -0,0 +1,141 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Добавить фильм - Online Cinema Theater</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигационная панель -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark-custom fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="index.html">
|
||||
<img src="resources/logo.webp" alt="Online Cinema Theater Logo" width="50" height="50" class="me-2">
|
||||
<span>Online Cinema Theater</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.html">Главная</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="catalog.html">Каталог</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="reviews.html">Рецензии</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
|
||||
Что глянуть?
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-dark">
|
||||
<li><a class="dropdown-item" href="films.html">Фильмы</a></li>
|
||||
<li><a class="dropdown-item" href="seriales.html">Сериалы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<main class="container py-5 mt-5">
|
||||
<section class="mb-5">
|
||||
<h2 class="text-orange mb-4"><i class="bi bi-plus-circle"></i> Добавить новый фильм</h2>
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto">
|
||||
<form id="addMovieForm" class="bg-dark p-4 rounded">
|
||||
<div class="mb-3">
|
||||
<label for="movieTitle" class="form-label text-light">
|
||||
<i class="bi bi-film"></i> Название фильма
|
||||
</label>
|
||||
<input type="text" class="form-control" id="movieTitle" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="movieDirector" class="form-label text-light">
|
||||
<i class="bi bi-person-video3"></i> Режиссер
|
||||
</label>
|
||||
<input type="text" class="form-control" id="movieDirector" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="movieGenre" class="form-label text-light">
|
||||
<i class="bi bi-tags"></i> Жанр
|
||||
</label>
|
||||
<select class="form-select" id="movieGenre" multiple required>
|
||||
<option value="action">Боевик</option>
|
||||
<option value="comedy">Комедия</option>
|
||||
<option value="drama">Драма</option>
|
||||
<option value="thriller">Триллер</option>
|
||||
<option value="horror">Ужасы</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="movieYear" class="form-label text-light">
|
||||
<i class="bi bi-calendar3"></i> Год выпуска
|
||||
</label>
|
||||
<input type="number" class="form-control" id="movieYear" min="1900" required>
|
||||
<small class="form-text text-muted">Год должен быть между 1900 и текущим годом</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="movieDescription" class="form-label text-light">
|
||||
<i class="bi bi-text-paragraph"></i> Описание
|
||||
</label>
|
||||
<textarea class="form-control" id="movieDescription" rows="3" required></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="moviePoster" class="form-label text-light">
|
||||
<i class="bi bi-image"></i> Постер фильма
|
||||
</label>
|
||||
<input type="file" class="form-control" id="moviePoster" accept="image/*" required>
|
||||
</div>
|
||||
<div class="preview-container mb-3 d-none">
|
||||
<img id="posterPreview" src="" alt="Preview" class="img-fluid rounded">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-orange w-100">
|
||||
<i class="bi bi-plus-circle-fill"></i> Добавить фильм
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Футер -->
|
||||
<footer class="footer-custom py-4">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3">
|
||||
<h5 class="text-white mb-3">Контактная информация</h5>
|
||||
<p>Телефон: +7 (123) 456-78-90</p>
|
||||
<p>Email: info@cinema.com</p>
|
||||
<p>Адрес: ул. Примерная, 123, Москва, Россия</p>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<h5 class="text-white mb-3">Мы в соцсетях</h5>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="#" class="text-light"><i class="bi bi-telegram fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-whatsapp fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-vk fs-4"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<h5 class="text-white mb-3">Время работы</h5>
|
||||
<p>Понедельник - Пятница: 10:00 - 22:00</p>
|
||||
<p>Суббота - Воскресенье: 12:00 - 24:00</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 text-center">
|
||||
<p class="mb-0">© 2022 Online Cinema Theater. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
166
catalog.html
Normal file
166
catalog.html
Normal file
@@ -0,0 +1,166 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Каталог - Online Cinema Theater</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<!-- Add CSS for consistent card sizes -->
|
||||
<style>
|
||||
.movie-card {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.movie-card .card-body {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.movie-card img.card-img-top {
|
||||
height: 400px;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигационная панель -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark-custom fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="index.html">
|
||||
<img src="resources/logo.webp" alt="Online Cinema Theater Logo" width="50" height="50" class="me-2">
|
||||
<span>Online Cinema Theater</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.html">Главная</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="catalog.html">Каталог</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="reviews.html">Рецензии</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
|
||||
Что глянуть?
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-dark">
|
||||
<li><a class="dropdown-item" href="films.html">Фильмы</a></li>
|
||||
<li><a class="dropdown-item" href="seriales.html">Сериалы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<main class="container py-5 mt-5">
|
||||
<section class="movie-catalog">
|
||||
<h2 class="text-orange mb-4">Каталог фильмов</h2>
|
||||
|
||||
<!-- Фильтры -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="genre-select" class="form-label"><i class="bi bi-funnel me-2"></i>Выберите жанр:</label>
|
||||
<select class="form-select" id="genre-select">
|
||||
<option value="all">Все жанры</option>
|
||||
<option value="action">Боевик</option>
|
||||
<option value="comedy">Комедия</option>
|
||||
<option value="drama">Драма</option>
|
||||
<option value="crime">Криминал</option>
|
||||
<option value="thriller">Триллер</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="year-select" class="form-label">Год выпуска:</label>
|
||||
<select class="form-select" id="year-select">
|
||||
<option value="all">Все годы</option>
|
||||
<option value="2024">2024</option>
|
||||
<option value="2023">2023</option>
|
||||
<option value="2022">2022</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="sort-select" class="form-label">Сортировка:</label>
|
||||
<select class="form-select" id="sort-select">
|
||||
<option value="rating">По рейтингу</option>
|
||||
<option value="date">По дате</option>
|
||||
<option value="name">По названию</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Movie Button -->
|
||||
<div class="mb-4 d-flex justify-content-end">
|
||||
<a href="add-movie.html" class="btn btn-success add-movie-btn">
|
||||
<i class="bi bi-plus-circle me-2"></i>Добавить фильм
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Movie Container -->
|
||||
<div id="movieContainer" class="row row-cols-1 row-cols-md-3 g-4">
|
||||
<!-- Movies will be loaded from localStorage -->
|
||||
</div>
|
||||
|
||||
<!-- Пагинация -->
|
||||
<nav class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" tabindex="-1"><i class="bi bi-chevron-left"></i> Предыдущая</a>
|
||||
</li>
|
||||
<li class="page-item active"><a class="page-link" href="#">1</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">2</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">3</a></li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#">Следующая <i class="bi bi-chevron-right"></i></a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Футер -->
|
||||
<footer class="bg-dark-custom text-light py-4">
|
||||
<div class="container">
|
||||
<div class="row gy-4">
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Контактная информация</h5>
|
||||
<p class="mb-1">Телефон: +7 (123) 456-78-90</p>
|
||||
<p class="mb-1">Email: info@cinema.com</p>
|
||||
<p>Адрес: ул. Примерная, 123, Москва, Россия</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Мы в соцсетях</h5>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="#" class="text-light"><i class="bi bi-telegram fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-whatsapp fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-vk fs-4"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Время работы</h5>
|
||||
<p class="mb-1">Понедельник - Пятница: 10:00 - 22:00</p>
|
||||
<p>Суббота - Воскресенье: 12:00 - 24:00</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col text-center">
|
||||
<p class="mb-0">© 2022 Online Cinema Theater. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
136
films.html
Normal file
136
films.html
Normal file
@@ -0,0 +1,136 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Фильмы - Online Cinema Theater</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<!-- Add CSS for consistent card sizes -->
|
||||
<style>
|
||||
.movie-card {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.movie-card .card-body {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.movie-card img.card-img-top {
|
||||
height: 400px;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигационная панель -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark-custom fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="index.html">
|
||||
<img src="resources/logo.webp" alt="Online Cinema Theater Logo" width="50" height="50" class="me-2">
|
||||
<span>Online Cinema Theater</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.html">Главная</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="catalog.html">Каталог</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="reviews.html">Рецензии</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown">
|
||||
Что глянуть?
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-dark">
|
||||
<li><a class="dropdown-item active" href="films.html">Фильмы</a></li>
|
||||
<li><a class="dropdown-item" href="seriales.html">Сериалы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<main class="container py-5 mt-5">
|
||||
<!-- Секция основных фильмов -->
|
||||
<section class="mb-5">
|
||||
<h2 class="text-orange mb-4">Основные фильмы</h2>
|
||||
|
||||
<!-- Add Movie Button -->
|
||||
<div class="mb-4 d-flex justify-content-end">
|
||||
<a href="add-movie.html" class="btn btn-success add-movie-btn">
|
||||
<i class="bi bi-plus-circle me-2"></i>Добавить фильм
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Movie Container -->
|
||||
<div id="movieContainer" class="row row-cols-1 row-cols-md-3 g-4">
|
||||
<!-- Movies will be loaded from localStorage -->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Секция предстоящих фильмов -->
|
||||
<section>
|
||||
<h2 class="text-orange mb-4">Предстоящие фильмы</h2>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-4 g-4">
|
||||
<div class="col">
|
||||
<div class="card movie-card h-100 bg-dark">
|
||||
<img src="resources/movies/gruz.jpeg" class="card-img-top" alt="Movie Poster">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title text-white"><i class="bi bi-film text-orange me-2"></i>Груз 200</h5>
|
||||
<p class="card-text text-white"><i class="bi bi-person-video3 me-2"></i>Режиссер: Алексей Балабанов</p>
|
||||
<p class="card-text text-light"><i class="bi bi-tags me-2"></i>Жанр: триллер, драма, криминал</p>
|
||||
<p class="card-text text-light"><i class="bi bi-calendar3 me-2"></i>Год выпуска: 2007</p>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent border-0">
|
||||
<a href="about.html" class="btn btn-orange w-100"><i class="bi bi-play-circle me-2"></i>Смотреть сейчас</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Футер -->
|
||||
<footer class="bg-dark-custom text-light py-4">
|
||||
<div class="container">
|
||||
<div class="row gy-4">
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Контактная информация</h5>
|
||||
<p class="mb-1">Телефон: +7 (123) 456-78-90</p>
|
||||
<p class="mb-1">Email: info@cinema.com</p>
|
||||
<p>Адрес: ул. Примерная, 123, Москва, Россия</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Мы в соцсетях</h5>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="#" class="text-light"><i class="bi bi-telegram fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-whatsapp fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-vk fs-4"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Время работы</h5>
|
||||
<p class="mb-1">Понедельник - Пятница: 10:00 - 22:00</p>
|
||||
<p>Суббота - Воскресенье: 12:00 - 24:00</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col text-center">
|
||||
<p class="mb-0">© 2022 Online Cinema Theater. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
124
index.html
124
index.html
@@ -1,12 +1,124 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Кинотеатр - React SPA</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Online Cinema Theater</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<!-- Add CSS for consistent card sizes -->
|
||||
<style>
|
||||
.movie-card {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.movie-card .card-body {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.movie-card img.card-img-top {
|
||||
height: 400px;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
<!-- Навигационная панель с использованием Bootstrap -->
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark-custom fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="index.html">
|
||||
<img src="resources/logo.webp" alt="Online Cinema Theater Logo" width="50" height="50" class="me-2">
|
||||
<span>Online Cinema Theater</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="index.html">Главная</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="catalog.html">Каталог</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="reviews.html">Рецензии</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Что глянуть?
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-dark" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="films.html">Фильмы</a></li>
|
||||
<li><a class="dropdown-item" href="seriales.html">Сериалы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<!-- Основное содержимое -->
|
||||
<main class="container py-5 mt-5">
|
||||
<div id="app">
|
||||
<section class="mb-5">
|
||||
<h2 class="text-orange mb-4">Популярные фильмы</h2>
|
||||
|
||||
<!-- Add Movie Button -->
|
||||
<div class="mb-4 d-flex justify-content-end">
|
||||
<a href="add-movie.html" class="btn btn-success add-movie-btn">
|
||||
<i class="bi bi-plus-circle me-2"></i>Добавить фильм
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Movie Container -->
|
||||
<div id="movieContainer" class="row row-cols-1 row-cols-md-3 g-4">
|
||||
<!-- Movies will be loaded from localStorage -->
|
||||
</div>
|
||||
|
||||
<!-- See All Button -->
|
||||
<div class="col-12 text-center mt-4">
|
||||
<a href="catalog.html" class="btn btn-primary">Смотреть все фильмы</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Футер -->
|
||||
<footer class="footer-custom py-4">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3">
|
||||
<h5 class="text-white mb-3">Контактная информация</h5>
|
||||
<p>Телефон: +7 (123) 456-78-90</p>
|
||||
<p>Email: info@cinema.com</p>
|
||||
<p>Адрес: ул. Примерная, 123, Москва, Россия</p>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<h5 class="text-white mb-3">Мы в соцсетях</h5>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="#" class="text-light"><i class="bi bi-telegram fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-whatsapp fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-vk fs-4"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<h5 class="text-white mb-3">Время работы</h5>
|
||||
<p>Понедельник - Пятница: 10:00 - 22:00</p>
|
||||
<p>Суббота - Воскресенье: 12:00 - 24:00</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 text-center">
|
||||
<p class="mb-0">© 2022 Online Cinema Theater. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
4665
package-lock.json
generated
4665
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@@ -6,10 +6,9 @@
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --ext .js,.jsx",
|
||||
"lint:fix": "eslint . --ext .js,.jsx --fix",
|
||||
"format": "prettier --write \"**/*.{js,jsx,html,css,json}\"",
|
||||
"server": "json-server --watch db.json --port 3000"
|
||||
"lint": "eslint . --ext .js",
|
||||
"lint:fix": "eslint . --ext .js --fix",
|
||||
"format": "prettier --write \"**/*.{js,html,css,json}\""
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -20,21 +19,14 @@
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint": "^9.22.0",
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"json-server": "^0.17.4",
|
||||
"prettier": "^3.2.5",
|
||||
"vite": "^5.2.6"
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"prettier": "^3.5.3",
|
||||
"vite": "^6.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^5.3.3",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.22.3"
|
||||
"bootstrap": "^5.3.2",
|
||||
"@popperjs/core": "^2.11.8"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 65 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.1 KiB |
126
reviews.html
Normal file
126
reviews.html
Normal file
@@ -0,0 +1,126 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Рецензии - Online Cinema Theater</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигационная панель -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark-custom fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="index.html">
|
||||
<img src="resources/logo.webp" alt="Online Cinema Theater Logo" width="50" height="50" class="me-2">
|
||||
<span>Online Cinema Theater</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.html">Главная</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="catalog.html">Каталог</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="reviews.html">Рецензии</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
|
||||
Что глянуть?
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-dark">
|
||||
<li><a class="dropdown-item" href="films.html">Фильмы</a></li>
|
||||
<li><a class="dropdown-item" href="seriales.html">Сериалы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<main class="container py-5 mt-5">
|
||||
<section class="movie-reviews">
|
||||
<h2 class="text-orange mb-4">Рецензии на фильмы</h2>
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<article class="card movie-card mb-4 bg-dark">
|
||||
<div class="row g-0">
|
||||
<div class="col-md-4">
|
||||
<img src="resources/movies/gruz.jpeg" class="img-fluid rounded-start" alt="Movie Poster">
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title text-white"><i class="bi bi-film text-orange me-2"></i>Груз 200</h5>
|
||||
<p class="card-text text-white"><i class="bi bi-person-video3 me-2"></i>Режиссер: Алексей Балабанов</p>
|
||||
<p class="card-text text-light"><i class="bi bi-tags me-2"></i>Жанр: триллер, драма, криминал</p>
|
||||
<p class="card-text text-light"><i class="bi bi-calendar3 me-2"></i>Год выпуска: 2007</p>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent border-0">
|
||||
<a href="about.html" class="btn btn-orange w-100"><i class="bi bi-play-circle me-2"></i>Смотреть сейчас</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card bg-dark-custom mb-4">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title text-orange">Популярные рецензии</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-3">
|
||||
<a href="#" class="text-decoration-none text-light">Топ-10 фильмов года</a>
|
||||
</li>
|
||||
<li class="mb-3">
|
||||
<a href="#" class="text-decoration-none text-light">Лучшие драмы 2024</a>
|
||||
</li>
|
||||
<li class="mb-3">
|
||||
<a href="#" class="text-decoration-none text-light">Новинки месяца</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Футер -->
|
||||
<footer class="bg-dark-custom text-light py-4">
|
||||
<div class="container">
|
||||
<div class="row gy-4">
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Контактная информация</h5>
|
||||
<p class="mb-1">Телефон: +7 (123) 456-78-90</p>
|
||||
<p class="mb-1">Email: info@cinema.com</p>
|
||||
<p>Адрес: ул. Примерная, 123, Москва, Россия</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Мы в соцсетях</h5>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="#" class="text-light"><i class="bi bi-telegram fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-whatsapp fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-vk fs-4"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Время работы</h5>
|
||||
<p class="mb-1">Понедельник - Пятница: 10:00 - 22:00</p>
|
||||
<p>Суббота - Воскресенье: 12:00 - 24:00</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col text-center">
|
||||
<p class="mb-0">© 2022 Online Cinema Theater. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
134
seriales.html
Normal file
134
seriales.html
Normal file
@@ -0,0 +1,134 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Сериалы - Online Cinema Theater</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигационная панель -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark-custom fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="index.html">
|
||||
<img src="resources/logo.webp" alt="Online Cinema Theater Logo" width="50" height="50" class="me-2">
|
||||
<span>Online Cinema Theater</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.html">Главная</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="catalog.html">Каталог</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="reviews.html">Рецензии</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown">
|
||||
Что глянуть?
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-dark">
|
||||
<li><a class="dropdown-item" href="films.html">Фильмы</a></li>
|
||||
<li><a class="dropdown-item active" href="seriales.html">Сериалы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<main class="container py-5 mt-5">
|
||||
<section class="featured-series">
|
||||
<h2 class="text-orange mb-4">Популярные сериалы</h2>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-4 g-4">
|
||||
<div class="col">
|
||||
<div class="card movie-card h-100 bg-dark">
|
||||
<img src="resources/series/960.webp" class="card-img-top" alt="Series Poster">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title text-white">Преступление и наказание</h5>
|
||||
<p class="card-text text-white">Сезонов: 1</p>
|
||||
<p class="card-text text-white">Серий: 8</p>
|
||||
<p class="card-text text-light">Год выпуска: 2007</p>
|
||||
<div class="progress mb-3" style="height: 5px;">
|
||||
<div class="progress-bar bg-warning" role="progressbar" style="width: 80%"></div>
|
||||
</div>
|
||||
<small class="text-light">Рейтинг: 8.0/10</small>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent border-0">
|
||||
<a href="about.html" class="btn btn-orange w-100">Смотреть сейчас</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mt-5">
|
||||
<h2 class="text-orange mb-4">Новые серии</h2>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-dark table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Название</th>
|
||||
<th scope="col">Сезон</th>
|
||||
<th scope="col">Серия</th>
|
||||
<th scope="col">Дата выхода</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Преступление и наказание</td>
|
||||
<td>1</td>
|
||||
<td>8</td>
|
||||
<td>01.04.2024</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Футер -->
|
||||
<footer class="bg-dark-custom text-light py-4">
|
||||
<div class="container">
|
||||
<div class="row gy-4">
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Контактная информация</h5>
|
||||
<p class="mb-1">Телефон: +7 (123) 456-78-90</p>
|
||||
<p class="mb-1">Email: info@cinema.com</p>
|
||||
<p>Адрес: ул. Примерная, 123, Москва, Россия</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Мы в соцсетях</h5>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="#" class="text-light"><i class="bi bi-telegram fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-whatsapp fs-4"></i></a>
|
||||
<a href="#" class="text-light"><i class="bi bi-vk fs-4"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5 class="mb-3">Время работы</h5>
|
||||
<p class="mb-1">Понедельник - Пятница: 10:00 - 22:00</p>
|
||||
<p>Суббота - Воскресенье: 12:00 - 24:00</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col text-center">
|
||||
<p class="mb-0">© 2022 Online Cinema Theater. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
74
src/App.jsx
74
src/App.jsx
@@ -1,74 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Routes, Route, Link } from 'react-router-dom';
|
||||
import HomePage from './pages/HomePage';
|
||||
import CatalogPage from './pages/CatalogPage';
|
||||
import AddMoviePage from './pages/AddMoviePage';
|
||||
import EditMoviePage from './pages/EditMoviePage';
|
||||
import AboutPage from './pages/AboutPage';
|
||||
import MovieDetailsPage from './pages/MovieDetailsPage';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div className="container">
|
||||
<Link className="navbar-brand" to="/">
|
||||
<i className="bi bi-film text-orange me-2"></i>
|
||||
Кинотеатр
|
||||
</Link>
|
||||
<button
|
||||
className="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span className="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div className="collapse navbar-collapse" id="navbarNav">
|
||||
<ul className="navbar-nav">
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/">Главная</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/catalog">Каталог</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/about">О нас</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div className="container py-4">
|
||||
<Routes>
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/catalog" element={<CatalogPage />} />
|
||||
<Route path="/add-movie" element={<AddMoviePage />} />
|
||||
<Route path="/edit-movie/:id" element={<EditMoviePage />} />
|
||||
<Route path="/movie/:id" element={<MovieDetailsPage />} />
|
||||
<Route path="/about" element={<AboutPage />} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
<footer className="bg-dark text-white py-4">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-md-6">
|
||||
<h5>Кинотеатр</h5>
|
||||
<p>Лучшие фильмы и сериалы в одном месте</p>
|
||||
</div>
|
||||
<div className="col-md-6 text-md-end">
|
||||
<p>© 2023 Кинотеатр. Все права защищены.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -1,56 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function MovieCard({ movie, onDelete }) {
|
||||
const handleDelete = () => {
|
||||
if (window.confirm('Вы уверены, что хотите удалить этот фильм?')) {
|
||||
onDelete(movie.id);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card movie-card h-100 bg-dark p-0">
|
||||
<img src={movie.poster} className="card-img-top" alt={`${movie.title} Poster`} />
|
||||
<div className="card-body">
|
||||
<h5 className="card-title text-white">
|
||||
<i className="bi bi-film text-orange me-2"></i>{movie.title}
|
||||
</h5>
|
||||
<p className="card-text text-white">
|
||||
<i className="bi bi-person-video3 text-secondary me-2"></i>{movie.director}
|
||||
</p>
|
||||
<p className="card-text text-light">
|
||||
<i className="bi bi-tags text-secondary me-2"></i>
|
||||
{Array.isArray(movie.genres) ? movie.genres.join(', ') : movie.genres}
|
||||
</p>
|
||||
<p className="card-text text-light">
|
||||
<i className="bi bi-calendar3 text-secondary me-2"></i>{movie.year}
|
||||
</p>
|
||||
{movie.description && (
|
||||
<div className="mt-3">
|
||||
<p className="card-text text-light small">
|
||||
<i className="bi bi-text-paragraph text-secondary me-2"></i>
|
||||
{movie.description.length > 100
|
||||
? movie.description.substring(0, 100) + '...'
|
||||
: movie.description}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="card-footer d-flex justify-content-between">
|
||||
<Link to={`/movie/${movie.id}`} className="btn btn-orange">
|
||||
<i className="bi bi-play-circle me-1"></i>Смотреть
|
||||
</Link>
|
||||
<div>
|
||||
<Link to={`/edit-movie/${movie.id}`} className="btn btn-outline-warning edit-movie me-1">
|
||||
<i className="bi bi-pencil"></i>
|
||||
</Link>
|
||||
<button className="btn btn-outline-danger delete-movie" onClick={handleDelete}>
|
||||
<i className="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MovieCard;
|
||||
@@ -1,129 +0,0 @@
|
||||
import React from 'react';
|
||||
import useMovieForm from '../../hooks/useMovieForm';
|
||||
|
||||
function MovieForm({ movie, onSubmit, isEditing = false }) {
|
||||
const {
|
||||
title, setTitle,
|
||||
director, setDirector,
|
||||
genres, handleGenreChange,
|
||||
year, setYear,
|
||||
description, setDescription,
|
||||
poster, handlePosterChange,
|
||||
previewVisible,
|
||||
getFormData
|
||||
} = useMovieForm(movie);
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
onSubmit(getFormData());
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="movieTitle" className="form-label">Название фильма</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
id="movieTitle"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label htmlFor="movieDirector" className="form-label">Режиссер</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
id="movieDirector"
|
||||
value={director}
|
||||
onChange={(e) => setDirector(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label htmlFor="movieGenre" className="form-label">Жанры</label>
|
||||
<select
|
||||
className="form-select"
|
||||
id="movieGenre"
|
||||
multiple
|
||||
value={genres}
|
||||
onChange={handleGenreChange}
|
||||
required
|
||||
>
|
||||
<option value="Боевик">Боевик</option>
|
||||
<option value="Комедия">Комедия</option>
|
||||
<option value="Драма">Драма</option>
|
||||
<option value="Фантастика">Фантастика</option>
|
||||
<option value="Ужасы">Ужасы</option>
|
||||
<option value="Триллер">Триллер</option>
|
||||
<option value="Детектив">Детектив</option>
|
||||
<option value="Приключения">Приключения</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label htmlFor="movieYear" className="form-label">Год выпуска</label>
|
||||
<input
|
||||
type="number"
|
||||
className="form-control"
|
||||
id="movieYear"
|
||||
min="1900"
|
||||
max={new Date().getFullYear()}
|
||||
value={year}
|
||||
onChange={(e) => setYear(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label htmlFor="movieDescription" className="form-label">Описание</label>
|
||||
<textarea
|
||||
className="form-control"
|
||||
id="movieDescription"
|
||||
rows="3"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label htmlFor="moviePoster" className="form-label">Постер</label>
|
||||
<input
|
||||
type="file"
|
||||
className="form-control"
|
||||
id="moviePoster"
|
||||
accept="image/*"
|
||||
onChange={handlePosterChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{previewVisible && (
|
||||
<div className="preview-container mb-3">
|
||||
<label className="form-label">Предпросмотр постера</label>
|
||||
<img
|
||||
src={poster}
|
||||
alt="Предпросмотр постера"
|
||||
id="posterPreview"
|
||||
className="img-thumbnail"
|
||||
style={{ maxHeight: '300px' }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="d-flex justify-content-between">
|
||||
<button type="submit" className="btn btn-primary">
|
||||
{isEditing ? 'Сохранить изменения' : 'Добавить фильм'}
|
||||
</button>
|
||||
<button type="button" className="btn btn-secondary" onClick={() => window.history.back()}>
|
||||
Отмена
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
export default MovieForm;
|
||||
@@ -1,45 +0,0 @@
|
||||
import React from 'react';
|
||||
import MovieCard from './MovieCard';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function MovieList({ movies, onDeleteMovie, isHomepage = false }) {
|
||||
// If we're on the homepage, only show up to 6 featured movies
|
||||
const moviesToShow = isHomepage ? movies.slice(0, 6) : movies;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-4 d-flex justify-content-between align-items-center">
|
||||
<h2 className={isHomepage ? "text-orange" : ""}>
|
||||
{isHomepage ? 'Популярные фильмы' : 'Каталог фильмов'}
|
||||
</h2>
|
||||
<Link to="/add-movie" className="btn btn-success">
|
||||
<i className="bi bi-plus-circle me-2"></i>Добавить фильм
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4" id="movieContainer">
|
||||
{moviesToShow.length > 0 ? (
|
||||
moviesToShow.map(movie => (
|
||||
<div className="col" key={movie.id}>
|
||||
<MovieCard movie={movie} onDelete={onDeleteMovie} />
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="col-12 text-center py-5">
|
||||
<p className="text-muted">Фильмы не найдены</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isHomepage && movies.length > 6 && (
|
||||
<div className="col-12 text-center mt-4">
|
||||
<Link to="/catalog" className="btn btn-primary">
|
||||
Смотреть все фильмы
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MovieList;
|
||||
@@ -1,47 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import MovieService from '../services/MovieService';
|
||||
|
||||
function useMovie(id) {
|
||||
const [movie, setMovie] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!id) {
|
||||
setLoading(false);
|
||||
setError('Movie ID is not provided.'); // Or handle as you see fit
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchMovie = async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const data = await MovieService.getMovieById(id);
|
||||
if (!data) {
|
||||
setError('Фильм не найден');
|
||||
setMovie(null); // Ensure movie state is reset if not found
|
||||
} else {
|
||||
setMovie(data);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error fetching movie:', err);
|
||||
setError('Не удалось загрузить данные фильма');
|
||||
setMovie(null); // Ensure movie state is reset on error
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchMovie();
|
||||
}, [id]); // Effect runs when the id changes
|
||||
|
||||
return {
|
||||
movie,
|
||||
loading,
|
||||
error,
|
||||
setMovie // It might be useful to allow manually setting the movie, e.g., after an update
|
||||
};
|
||||
}
|
||||
|
||||
export default useMovie;
|
||||
@@ -1,80 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
function useMovieForm(initialMovieData = null) {
|
||||
const [title, setTitle] = useState('');
|
||||
const [director, setDirector] = useState('');
|
||||
const [genres, setGenres] = useState([]);
|
||||
const [year, setYear] = useState('');
|
||||
const [description, setDescription] = useState('');
|
||||
const [poster, setPoster] = useState('');
|
||||
const [previewVisible, setPreviewVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialMovieData) {
|
||||
setTitle(initialMovieData.title || '');
|
||||
setDirector(initialMovieData.director || '');
|
||||
setGenres(Array.isArray(initialMovieData.genres) ? initialMovieData.genres : []);
|
||||
setYear(initialMovieData.year || '');
|
||||
setDescription(initialMovieData.description || '');
|
||||
setPoster(initialMovieData.poster || '');
|
||||
if (initialMovieData.poster) {
|
||||
setPreviewVisible(true);
|
||||
} else {
|
||||
setPreviewVisible(false); // Ensure preview is hidden if no poster
|
||||
}
|
||||
} else {
|
||||
// Reset form if no initial data (e.g., for add form after an edit)
|
||||
setTitle('');
|
||||
setDirector('');
|
||||
setGenres([]);
|
||||
setYear('');
|
||||
setDescription('');
|
||||
setPoster('');
|
||||
setPreviewVisible(false);
|
||||
}
|
||||
}, [initialMovieData]);
|
||||
|
||||
const handleGenreChange = (e) => {
|
||||
const selectedGenres = Array.from(e.target.selectedOptions).map(option => option.value);
|
||||
setGenres(selectedGenres);
|
||||
};
|
||||
|
||||
const handlePosterChange = (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
setPoster(event.target.result);
|
||||
setPreviewVisible(true);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
// If no file is selected, or selection is cancelled
|
||||
// setPoster(''); // Optionally clear poster if no file is chosen
|
||||
// setPreviewVisible(false); // Optionally hide preview
|
||||
}
|
||||
};
|
||||
|
||||
const getFormData = () => ({
|
||||
title,
|
||||
director,
|
||||
genres,
|
||||
year,
|
||||
description,
|
||||
poster
|
||||
});
|
||||
|
||||
// Exposed state and handlers
|
||||
return {
|
||||
title, setTitle,
|
||||
director, setDirector,
|
||||
genres, setGenres, handleGenreChange, // Expose specific handler for genres
|
||||
year, setYear,
|
||||
description, setDescription,
|
||||
poster, setPoster, handlePosterChange, // Expose specific handler for poster
|
||||
previewVisible,
|
||||
getFormData // Function to get all form data for submission
|
||||
};
|
||||
}
|
||||
|
||||
export default useMovieForm;
|
||||
@@ -1,71 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import MovieService from '../services/MovieService';
|
||||
|
||||
function useMovies() {
|
||||
const [movies, setMovies] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [selectedGenre, setSelectedGenre] = useState('');
|
||||
const [genres, setGenres] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchMoviesAndGenres = async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const data = await MovieService.getMovies();
|
||||
setMovies(data);
|
||||
|
||||
const allGenres = data.flatMap(movie => movie.genres || []);
|
||||
const uniqueGenres = [...new Set(allGenres)];
|
||||
setGenres(uniqueGenres);
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error fetching movies:', err);
|
||||
setError('Не удалось загрузить фильмы. Пожалуйста, попробуйте позже.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchMoviesAndGenres();
|
||||
}, []);
|
||||
|
||||
const handleDeleteMovie = async (id) => {
|
||||
try {
|
||||
await MovieService.deleteMovie(id);
|
||||
setMovies(prevMovies => prevMovies.filter(movie => movie.id !== id));
|
||||
} catch (err) {
|
||||
console.error('Error deleting movie:', err);
|
||||
alert('Произошла ошибка при удалении фильма.');
|
||||
// Optionally, re-throw or set an error state for the component to handle
|
||||
}
|
||||
};
|
||||
|
||||
const filteredMovies = movies.filter(movie => {
|
||||
const matchesSearch = searchTerm ?
|
||||
(movie.title?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
movie.director?.toLowerCase().includes(searchTerm.toLowerCase())) : true;
|
||||
|
||||
const matchesGenre = selectedGenre === '' ||
|
||||
(Array.isArray(movie.genres) && movie.genres.includes(selectedGenre));
|
||||
|
||||
return matchesSearch && matchesGenre;
|
||||
});
|
||||
|
||||
return {
|
||||
movies: filteredMovies, // Return filtered movies
|
||||
loading,
|
||||
error,
|
||||
searchTerm,
|
||||
setSearchTerm,
|
||||
selectedGenre,
|
||||
setSelectedGenre,
|
||||
genres, // Original list of unique genres for the dropdown
|
||||
handleDeleteMovie,
|
||||
allMovies: movies // Raw list of movies if needed elsewhere, though typically not exposed directly
|
||||
};
|
||||
}
|
||||
|
||||
export default useMovies;
|
||||
217
src/main.js
Normal file
217
src/main.js
Normal file
@@ -0,0 +1,217 @@
|
||||
// Импортируем Bootstrap
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
|
||||
|
||||
// Импортируем собственные стили
|
||||
import '../style.css';
|
||||
|
||||
// Инициализация общего функционала сайта
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
console.log('Сайт успешно загружен!');
|
||||
|
||||
// Инициализация выпадающего меню, если оно есть на странице
|
||||
const dropdownElements = document.querySelectorAll('.dropdown');
|
||||
if (dropdownElements.length > 0) {
|
||||
dropdownElements.forEach(dropdown => {
|
||||
dropdown.addEventListener('click', () => {
|
||||
dropdown.querySelector('.features-menu')?.classList.toggle('active');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Set max year to current year for the year input
|
||||
const movieYearInput = document.getElementById('movieYear');
|
||||
if (movieYearInput) {
|
||||
const currentYear = new Date().getFullYear();
|
||||
// Only set the min attribute, validation will happen on form submission
|
||||
movieYearInput.min = 1900;
|
||||
}
|
||||
|
||||
// Добавление обработчиков для фильтров в каталоге
|
||||
const genreSelect = document.getElementById('genre-select');
|
||||
if (genreSelect) {
|
||||
genreSelect.addEventListener('change', () => {
|
||||
// Здесь будет логика фильтрации по жанрам
|
||||
console.log('Выбран жанр:', genreSelect.value);
|
||||
});
|
||||
}
|
||||
|
||||
// Load movies from localStorage and display them
|
||||
const movieContainer = document.getElementById('movieContainer');
|
||||
if (movieContainer) {
|
||||
loadMoviesFromStorage();
|
||||
}
|
||||
|
||||
// Form submission handler
|
||||
const addMovieForm = document.getElementById('addMovieForm');
|
||||
if (addMovieForm) {
|
||||
// Handle poster preview
|
||||
const moviePoster = document.getElementById('moviePoster');
|
||||
const posterPreview = document.getElementById('posterPreview');
|
||||
const previewContainer = document.querySelector('.preview-container');
|
||||
|
||||
if (moviePoster && posterPreview && previewContainer) {
|
||||
moviePoster.addEventListener('change', (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
posterPreview.src = e.target.result;
|
||||
previewContainer.classList.remove('d-none');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addMovieForm.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
// Get form values
|
||||
const title = document.getElementById('movieTitle').value;
|
||||
const director = document.getElementById('movieDirector').value;
|
||||
const year = parseInt(document.getElementById('movieYear').value);
|
||||
const currentYear = new Date().getFullYear();
|
||||
let errorText = ""
|
||||
// Validate year only on form submission
|
||||
if (year > currentYear) {
|
||||
errorText += `Год выпуска не может быть больше текущего (${currentYear})\n`;
|
||||
}
|
||||
|
||||
if (year < 1900) {
|
||||
errorText += "Год выпуска не может быть меньше 1900\n";
|
||||
}
|
||||
|
||||
// Check if movie already exists
|
||||
if (movieExists(title, director)) {
|
||||
errorText += "Фильм с таким названием и режиссером уже существует!\n";
|
||||
}
|
||||
if (errorText) {
|
||||
alert(errorText)
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = {
|
||||
id: Date.now().toString(), // Generate unique ID based on timestamp
|
||||
title: title,
|
||||
director: director,
|
||||
genres: Array.from(document.getElementById('movieGenre').selectedOptions).map(option => option.text),
|
||||
year: year,
|
||||
description: document.getElementById('movieDescription').value,
|
||||
poster: posterPreview?.src || 'resources/movies/placeholder.jpg'
|
||||
};
|
||||
|
||||
// Save to localStorage
|
||||
if (saveMovieToStorage(formData)) {
|
||||
// Reset form and preview
|
||||
addMovieForm.reset();
|
||||
if (previewContainer) {
|
||||
previewContainer.classList.add('d-none');
|
||||
}
|
||||
|
||||
// Show success message
|
||||
alert('Фильм успешно добавлен!');
|
||||
|
||||
// Redirect to catalog page if we're on the add-movie page
|
||||
if (window.location.pathname.includes('add-movie.html')) {
|
||||
window.location.href = 'catalog.html';
|
||||
} else if (movieContainer) {
|
||||
// If we're already on a page with the movie container, add the new card
|
||||
addMovieCard(formData, movieContainer);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Function to create movie card
|
||||
function createMovieCard(movie) {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card movie-card h-100 bg-dark';
|
||||
card.dataset.movieId = movie.id;
|
||||
|
||||
card.innerHTML = `
|
||||
<img src="${movie.poster}" class="card-img-top" alt="${movie.title} Poster">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title text-white"><i class="bi bi-film text-orange me-2"></i>${movie.title}</h5>
|
||||
<p class="card-text text-white"><i class="bi bi-person-video3 me-2"></i>Режиссер: ${movie.director}</p>
|
||||
<p class="card-text text-light"><i class="bi bi-tags me-2"></i>Жанр: ${Array.isArray(movie.genres) ? movie.genres.join(', ') : movie.genres}</p>
|
||||
<p class="card-text text-light"><i class="bi bi-calendar3 me-2"></i>Год выпуска: ${movie.year}</p>
|
||||
${movie.description ? `<p class="card-text text-light"><i class="bi bi-text-paragraph me-2"></i>Описание: ${movie.description}</p>` : ''}
|
||||
</div>
|
||||
<div class="card-footer bg-transparent border-0 d-flex justify-content-between">
|
||||
<a href="about.html" class="btn btn-orange"><i class="bi bi-play-circle me-2"></i>Смотреть</a>
|
||||
<button class="btn btn-danger delete-movie"><i class="bi bi-trash"></i> Удалить</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Add event listener for delete button
|
||||
const deleteButton = card.querySelector('.delete-movie');
|
||||
if (deleteButton) {
|
||||
deleteButton.addEventListener('click', () => {
|
||||
if (confirm('Вы уверены, что хотите удалить этот фильм?')) {
|
||||
deleteMovieFromStorage(movie.id);
|
||||
card.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
// Function to add a movie card to the container
|
||||
function addMovieCard(movie, container) {
|
||||
const colDiv = document.createElement('div');
|
||||
colDiv.className = 'col';
|
||||
const movieCard = createMovieCard(movie);
|
||||
colDiv.appendChild(movieCard);
|
||||
container.prepend(colDiv);
|
||||
}
|
||||
|
||||
// Function to check if a movie already exists in localStorage
|
||||
function movieExists(title, director) {
|
||||
const movies = JSON.parse(localStorage.getItem('movies')) || [];
|
||||
return movies.some(movie =>
|
||||
movie.title.toLowerCase() === title.toLowerCase() &&
|
||||
movie.director.toLowerCase() === director.toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
// Function to save movie to localStorage
|
||||
function saveMovieToStorage(movie) {
|
||||
// Get existing movies from localStorage
|
||||
const movies = JSON.parse(localStorage.getItem('movies')) || [];
|
||||
|
||||
// Add new movie
|
||||
movies.push(movie);
|
||||
|
||||
// Save back to localStorage
|
||||
localStorage.setItem('movies', JSON.stringify(movies));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function to delete movie from localStorage
|
||||
function deleteMovieFromStorage(movieId) {
|
||||
// Get existing movies from localStorage
|
||||
let movies = JSON.parse(localStorage.getItem('movies')) || [];
|
||||
|
||||
// Filter out the movie to delete
|
||||
movies = movies.filter(movie => movie.id !== movieId);
|
||||
|
||||
// Save back to localStorage
|
||||
localStorage.setItem('movies', JSON.stringify(movies));
|
||||
}
|
||||
|
||||
// Function to load movies from localStorage and display them
|
||||
function loadMoviesFromStorage() {
|
||||
const movieContainer = document.getElementById('movieContainer');
|
||||
if (!movieContainer) return;
|
||||
|
||||
// Get movies from localStorage
|
||||
const movies = JSON.parse(localStorage.getItem('movies')) || [];
|
||||
|
||||
// Display each movie
|
||||
movies.forEach(movie => {
|
||||
addMovieCard(movie, movieContainer);
|
||||
});
|
||||
}
|
||||
17
src/main.jsx
17
src/main.jsx
@@ -1,17 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import App from './App';
|
||||
|
||||
// Import Bootstrap
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'bootstrap-icons/font/bootstrap-icons.css';
|
||||
import './style.css';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<React.StrictMode>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>
|
||||
);
|
||||
@@ -1,23 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
function AboutPage() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="mb-4">О нас</h2>
|
||||
<div className="card bg-dark text-white">
|
||||
<div className="card-body">
|
||||
<h5 className="card-title">Наш кинотеатр</h5>
|
||||
<p className="card-text">
|
||||
Мы предлагаем широкий выбор фильмов различных жанров и направлений.
|
||||
Наша цель - сделать просмотр кино максимально комфортным и приятным для вас.
|
||||
</p>
|
||||
<p className="card-text">
|
||||
Наслаждайтесь просмотром любимых фильмов в отличном качестве!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AboutPage;
|
||||
@@ -1,28 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import MovieForm from '../components/Movie/MovieForm';
|
||||
import MovieService from '../services/MovieService';
|
||||
|
||||
function AddMoviePage() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleAddMovie = async (movieData) => {
|
||||
try {
|
||||
await MovieService.addMovie(movieData);
|
||||
alert('Фильм успешно добавлен!');
|
||||
navigate('/catalog');
|
||||
} catch (error) {
|
||||
console.error('Error adding movie:', error);
|
||||
alert('Произошла ошибка при добавлении фильма.');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="mb-4">Добавить новый фильм</h2>
|
||||
<MovieForm onSubmit={handleAddMovie} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddMoviePage;
|
||||
@@ -1,62 +0,0 @@
|
||||
import React from 'react';
|
||||
import MovieList from '../components/Movie/MovieList';
|
||||
// import MovieService from '../services/MovieService'; // No longer needed here
|
||||
import useMovies from '../hooks/useMovies'; // Import the custom hook
|
||||
|
||||
function CatalogPage() {
|
||||
const {
|
||||
movies, // This is now filteredMovies from the hook
|
||||
loading,
|
||||
error,
|
||||
searchTerm,
|
||||
setSearchTerm,
|
||||
selectedGenre,
|
||||
setSelectedGenre,
|
||||
genres, // This is the unique genres list from the hook
|
||||
handleDeleteMovie
|
||||
} = useMovies();
|
||||
|
||||
// useEffect and handleDeleteMovie logic is now in useMovies hook
|
||||
// Filtered movies logic is also in useMovies hook
|
||||
|
||||
if (loading) {
|
||||
return <div className="text-center py-5"><div className="spinner-border" role="status"></div></div>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <div className="alert alert-danger">{error}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="row mb-4">
|
||||
<div className="col-md-6 mb-3">
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="Поиск по названию или режиссеру"
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-md-6 mb-3">
|
||||
<select
|
||||
className="form-select"
|
||||
value={selectedGenre}
|
||||
onChange={(e) => setSelectedGenre(e.target.value)}
|
||||
>
|
||||
<option value="">Все жанры</option>
|
||||
{genres.map(genre => (
|
||||
<option key={genre} value={genre}>{genre}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Pass the movies (which are already filtered) and onDeleteMovie from the hook */}
|
||||
<MovieList movies={movies} onDeleteMovie={handleDeleteMovie} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CatalogPage;
|
||||
@@ -1,43 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import MovieForm from '../components/Movie/MovieForm';
|
||||
import MovieService from '../services/MovieService';
|
||||
import useMovie from '../hooks/useMovie';
|
||||
|
||||
function EditMoviePage() {
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const { movie, loading, error, setMovie } = useMovie(id);
|
||||
|
||||
const handleUpdateMovie = async (movieData) => {
|
||||
try {
|
||||
const updatedMovie = await MovieService.updateMovie(id, movieData);
|
||||
alert('Фильм успешно обновлен!');
|
||||
navigate('/catalog');
|
||||
} catch (err) {
|
||||
console.error('Error updating movie:', err);
|
||||
alert('Произошла ошибка при обновлении фильма.');
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div className="text-center py-5"><div className="spinner-border" role="status"></div></div>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <div className="alert alert-danger">{error}</div>;
|
||||
}
|
||||
|
||||
if (!movie) {
|
||||
return <div className="alert alert-warning">Фильм для редактирования не найден.</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="mb-4">Редактировать фильм</h2>
|
||||
<MovieForm movie={movie} onSubmit={handleUpdateMovie} isEditing={true} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditMoviePage;
|
||||
@@ -1,60 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import MovieList from '../components/Movie/MovieList';
|
||||
import MovieService from '../services/MovieService';
|
||||
|
||||
function HomePage() {
|
||||
const [movies, setMovies] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchMovies = async () => {
|
||||
try {
|
||||
const data = await MovieService.getMovies();
|
||||
// Sort by year (newest first) for featured movies
|
||||
const sortedMovies = [...data].sort((a, b) => b.year - a.year);
|
||||
setMovies(sortedMovies);
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error('Error fetching movies:', error);
|
||||
setError('Не удалось загрузить фильмы. Пожалуйста, попробуйте позже.');
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchMovies();
|
||||
}, []);
|
||||
|
||||
const handleDeleteMovie = async (id) => {
|
||||
try {
|
||||
await MovieService.deleteMovie(id);
|
||||
setMovies(movies.filter(movie => movie.id !== id));
|
||||
} catch (error) {
|
||||
console.error('Error deleting movie:', error);
|
||||
alert('Произошла ошибка при удалении фильма.');
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div className="text-center py-5"><div className="spinner-border" role="status"></div></div>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <div className="alert alert-danger">{error}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="jumbotron bg-dark text-white p-5 mb-4 rounded">
|
||||
<h1 className="display-4">Добро пожаловать в наш кинотеатр!</h1>
|
||||
<p className="lead">Лучшие фильмы и сериалы в одном месте</p>
|
||||
<hr className="my-4" />
|
||||
<p>Смотрите новинки кино и классику в отличном качестве</p>
|
||||
</div>
|
||||
|
||||
<MovieList movies={movies} onDeleteMovie={handleDeleteMovie} isHomepage={true} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default HomePage;
|
||||
@@ -1,61 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useParams, Link } from 'react-router-dom';
|
||||
import useMovie from '../hooks/useMovie';
|
||||
|
||||
function MovieDetailsPage() {
|
||||
const { id } = useParams();
|
||||
const { movie, loading, error } = useMovie(id);
|
||||
|
||||
if (loading) {
|
||||
return <div className="text-center py-5"><div className="spinner-border" role="status"></div></div>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <div className="alert alert-danger">{error}</div>;
|
||||
}
|
||||
|
||||
if (!movie) {
|
||||
return <div className="alert alert-warning">Фильм не найден.</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mt-5">
|
||||
<div className="row">
|
||||
<div className="col-md-4">
|
||||
<img src={movie.poster} className="img-fluid rounded shadow-sm" alt={`${movie.title} Poster`} />
|
||||
</div>
|
||||
<div className="col-md-8">
|
||||
<h1 className="mb-3 text-orange">{movie.title}</h1>
|
||||
<p className="lead">
|
||||
<i className="bi bi-person-video3 text-secondary me-2"></i>
|
||||
<strong>Режиссер:</strong> {movie.director}
|
||||
</p>
|
||||
<p>
|
||||
<i className="bi bi-calendar3 text-secondary me-2"></i>
|
||||
<strong>Год:</strong> {movie.year}
|
||||
</p>
|
||||
<p>
|
||||
<i className="bi bi-tags text-secondary me-2"></i>
|
||||
<strong>Жанры:</strong> {Array.isArray(movie.genres) ? movie.genres.join(', ') : movie.genres}
|
||||
</p>
|
||||
<hr />
|
||||
<h5 className="mt-4 mb-3">Описание:</h5>
|
||||
<p style={{ textAlign: 'justify' }}>{movie.description}</p>
|
||||
<hr />
|
||||
<div className="mt-4">
|
||||
<Link to={`/edit-movie/${movie.id}`} className="btn btn-warning me-2">
|
||||
<i className="bi bi-pencil me-1"></i> Редактировать
|
||||
</Link>
|
||||
<Link to="/catalog" className="btn btn-outline-secondary">
|
||||
<i className="bi bi-arrow-left-circle me-1"></i> Назад к каталогу
|
||||
</Link>
|
||||
{/* Placeholder for a play button or video embed area */}
|
||||
{/* <button className=\"btn btn-lg btn-success mt-3 w-100\">Смотреть фильм</button> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MovieDetailsPage;
|
||||
@@ -1,82 +0,0 @@
|
||||
const API_URL = 'http://localhost:3000';
|
||||
|
||||
export default class MovieService {
|
||||
static async getMovies() {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/movies`);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch movies');
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching movies:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
static async getMovieById(id) {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/movies/${id}`);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch movie');
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching movie:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static async addMovie(movie) {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/movies`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(movie)
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to add movie');
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error adding movie:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
static async updateMovie(id, movie) {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/movies/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(movie)
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to update movie');
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error updating movie:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
static async deleteMovie(id) {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/movies/${id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to delete movie');
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error deleting movie:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
150
src/style.css
150
src/style.css
@@ -1,150 +0,0 @@
|
||||
/* Custom styles for the movie application */
|
||||
.btn-orange {
|
||||
background-color: #fd7e14;
|
||||
color: white;
|
||||
}
|
||||
.btn-orange:hover {
|
||||
background-color: #e76b00;
|
||||
color: white;
|
||||
}
|
||||
.text-orange {
|
||||
color: #fd7e14 !important;
|
||||
}
|
||||
|
||||
/* Redesigned movie card styling */
|
||||
.movie-card {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
background-color: #212529 !important;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 6px 12px rgba(0,0,0,0.15);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
.movie-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 12px 16px rgba(0,0,0,0.2);
|
||||
}
|
||||
.movie-card .card-body {
|
||||
flex: 1 1 auto;
|
||||
padding: 1.25rem;
|
||||
}
|
||||
.card-img-top {
|
||||
height: 380px;
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
}
|
||||
.movie-card .card-title {
|
||||
font-size: 1.25rem;
|
||||
margin-bottom: 0.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.movie-card .card-text {
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.movie-card .card-footer {
|
||||
background-color: rgba(0,0,0,0.1) !important;
|
||||
border-top: none !important;
|
||||
padding: 0.75rem 1.25rem;
|
||||
}
|
||||
.movie-card .btn {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Animation for card deletion */
|
||||
.movie-card.deleting {
|
||||
animation: fadeOut 0.5s ease forwards;
|
||||
}
|
||||
@keyframes fadeOut {
|
||||
from { opacity: 1; transform: scale(1); }
|
||||
to { opacity: 0; transform: scale(0.8); }
|
||||
}
|
||||
|
||||
/* Form styling */
|
||||
.preview-container {
|
||||
max-width: 300px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* Jumbotron styling for homepage */
|
||||
.jumbotron {
|
||||
background-color: #212529;
|
||||
border-radius: 0.5rem;
|
||||
padding: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
body {
|
||||
background-color: #131516;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* Global text color adjustments */
|
||||
h1, h2, h3, h4, h5, h6, p, span, div, label, a {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
.form-control, .form-select {
|
||||
background-color: #212529;
|
||||
color: #f8f9fa;
|
||||
border-color: #495057;
|
||||
}
|
||||
|
||||
.form-control:focus, .form-select:focus {
|
||||
background-color: #2c3034;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* Add these styles for placeholder text */
|
||||
.form-control::placeholder {
|
||||
color: #adb5bd;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* For Firefox */
|
||||
.form-control::-moz-placeholder {
|
||||
color: #adb5bd;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* For Internet Explorer */
|
||||
.form-control:-ms-input-placeholder {
|
||||
color: #adb5bd;
|
||||
}
|
||||
|
||||
/* For Microsoft Edge */
|
||||
.form-control::-ms-input-placeholder {
|
||||
color: #adb5bd;
|
||||
}
|
||||
.card {
|
||||
background-color: #212529;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
.alert {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: #adb5bd !important;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: #fd7e14;
|
||||
}
|
||||
53
style.css
Normal file
53
style.css
Normal file
@@ -0,0 +1,53 @@
|
||||
/* Минимальные настройки внешнего вида */
|
||||
body {
|
||||
background-color: #121212;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Кастомные цвета для элементов */
|
||||
.bg-dark-custom {
|
||||
background-color: #222222;
|
||||
}
|
||||
|
||||
.text-orange {
|
||||
color: #ff6600 !important;
|
||||
}
|
||||
|
||||
.btn-orange {
|
||||
background-color: #ff6600;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-orange:hover {
|
||||
background-color: #e55c00;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Стили для карточек фильмов */
|
||||
.movie-card {
|
||||
background-color: #222222;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.movie-card:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
/* Стили для футера */
|
||||
.footer-custom {
|
||||
background-color: #222222;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* Стили для социальных иконок */
|
||||
.social-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.social-icon:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
60
template.html
Normal file
60
template.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Page Title</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<div class="logo">
|
||||
<img src="resources/logo.webp" alt="Online Cinema Theater Logo">
|
||||
<span>Online Cinema Theater</span>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="navbar">
|
||||
<li><a href="index.html">Главная</a></li>
|
||||
<li><a href="catalog.html">Каталог</a></li>
|
||||
<li><a href="reviews.html">Рецензии</a></li>
|
||||
<li class="dropdown">
|
||||
<span>Что глянуть? ▾</span>
|
||||
<ul class="features-menu">
|
||||
<li><a href="films.html">Фильмы</a></li>
|
||||
<li><a href="seriales.html">Сериалы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
<section class="content">
|
||||
<!-- Main content goes here -->
|
||||
</section>
|
||||
</main>
|
||||
<footer>
|
||||
<div class="footer-container">
|
||||
<div class="contact-info">
|
||||
<h3>Контактная информация</h3>
|
||||
<p>Телефон: +7 (123) 456-78-90</p>
|
||||
<p>Email: info@cinema.com</p>
|
||||
<p>Адрес: ул. Примерная, 123, Москва, Россия</p>
|
||||
</div>
|
||||
<div class="social-media">
|
||||
<h3>Мы в соцсетях</h3>
|
||||
<a href="#"><img src="resources/icons/icq.svg" alt="ICQ"></a>
|
||||
<a href="#"><img src="resources/icons/tg.webp" alt="Telegram"></a>
|
||||
<a href="#"><img src="resources/icons/vk.webp" alt="VK"></a>
|
||||
</div>
|
||||
<div class="working-hours">
|
||||
<h3>Время работы</h3>
|
||||
<p>Понедельник - Пятница: 10:00 - 22:00</p>
|
||||
<p>Суббота - Воскресенье: 12:00 - 24:00</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>© 2022 Online Cinema Theater. All rights reserved.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,18 +1,32 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import { resolve } from 'path';
|
||||
import react from '@vitejs/plugin-react';
|
||||
|
||||
// Получаем список HTML-файлов для мультистраничного приложения
|
||||
const pages = [
|
||||
'index.html',
|
||||
'catalog.html',
|
||||
'films.html',
|
||||
'seriales.html',
|
||||
'reviews.html',
|
||||
'about.html',
|
||||
'add-movie.html' // Add this line
|
||||
];
|
||||
|
||||
// Создаем объект с входными точками для каждой страницы
|
||||
const input = {};
|
||||
pages.forEach(page => {
|
||||
input[page.replace('.html', '')] = resolve(__dirname, page);
|
||||
});
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
root: './',
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, 'src')
|
||||
rollupOptions: {
|
||||
input
|
||||
}
|
||||
},
|
||||
server: {
|
||||
open: true
|
||||
open: '/index.html'
|
||||
}
|
||||
});
|
||||
BIN
Отчет.docx
BIN
Отчет.docx
Binary file not shown.
Reference in New Issue
Block a user