labwork05 with report
This commit is contained in:
50
.gitignore
vendored
50
.gitignore
vendored
@@ -1,12 +1,42 @@
|
|||||||
# Node.js dependencies
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Build output
|
# Compiled output
|
||||||
dist/
|
/dist
|
||||||
build/
|
/tmp
|
||||||
out/
|
/out-tsc
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
# Environment variables
|
# Node
|
||||||
.env
|
/node_modules
|
||||||
.env.local
|
npm-debug.log
|
||||||
.env.*.local
|
yarn-error.log
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea/
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
/.angular/cache
|
||||||
|
.sass-cache/
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|||||||
7
.prettierrc
Normal file
7
.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"tabWidth": 4,
|
||||||
|
"singleQuote": false,
|
||||||
|
"printWidth": 120,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"useTabs": false
|
||||||
|
}
|
||||||
17
README.md
Normal file
17
README.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Установка зависимостей
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
Запуск в режиме разработки
|
||||||
|
|
||||||
|
```
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
Запуск для использования в продуктовой среде
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run prod
|
||||||
|
```
|
||||||
16
db.json
16
db.json
@@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
"movies": [
|
"movies": [
|
||||||
{
|
|
||||||
"id": "ebed",
|
|
||||||
"title": "ФФФФФФФФФфф",
|
|
||||||
"imageUrl": "https://avatars.mds.yandex.net/i?id=8e077526d7dfae9d31827e81fea4e74c_l-5233298-images-thumbs&n=13"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "8fd8",
|
"id": "8fd8",
|
||||||
"title": "ittifaq",
|
"title": "ittifaqq",
|
||||||
"imageUrl": "https://avatars.mds.yandex.net/i?id=17b83f995e81ac7426335d0659a050263d567f34-13135934-images-thumbs&n=13"
|
"poster": "https://avatars.mds.yandex.net/i?id=17b83f995e81ac7426335d0659a050263d567f34-13135934-images-thumbs&n=13"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "5267",
|
"id": "5267",
|
||||||
"title": "priora",
|
"title": "priora",
|
||||||
"imageUrl": "https://ir-3.ozone.ru/s3/multimedia-8/w1200/6738078680.jpg"
|
"poster": "https://ir-3.ozone.ru/s3/multimedia-8/w1200/6738078680.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2756",
|
||||||
|
"title": "Bibiziyana",
|
||||||
|
"poster": "https://avatars.mds.yandex.net/i?id=eeaf22011f8c07976795a01b40f431b0f42c8f43-5100713-images-thumbs&n=13"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
49
eslint.config.js
Normal file
49
eslint.config.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import js from "@eslint/js";
|
||||||
|
import eslintConfigPrettier from "eslint-config-prettier/flat";
|
||||||
|
import pluginImport from "eslint-plugin-import";
|
||||||
|
import reactPlugin from "eslint-plugin-react";
|
||||||
|
import reactHooks from "eslint-plugin-react-hooks";
|
||||||
|
import reactRefresh from "eslint-plugin-react-refresh";
|
||||||
|
import globals from "globals";
|
||||||
|
import viteConfigObj from "./vite.config.js";
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{ ignores: ["dist", "vite.config.js"] },
|
||||||
|
{
|
||||||
|
files: ["**/*.{js,jsx}"],
|
||||||
|
languageOptions: {
|
||||||
|
globals: globals.browser,
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
react: {
|
||||||
|
version: "detect",
|
||||||
|
},
|
||||||
|
"import/resolver": {
|
||||||
|
node: {
|
||||||
|
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
||||||
|
},
|
||||||
|
vite: {
|
||||||
|
viteConfig: viteConfigObj,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
react: reactPlugin,
|
||||||
|
"react-hooks": reactHooks,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
js.configs.recommended,
|
||||||
|
pluginImport.flatConfigs.recommended,
|
||||||
|
reactRefresh.configs.recommended,
|
||||||
|
reactPlugin.configs.flat.recommended,
|
||||||
|
reactPlugin.configs.flat["jsx-runtime"],
|
||||||
|
eslintConfigPrettier,
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
...reactHooks.configs.recommended.rules,
|
||||||
|
"no-unused-vars": ["error", { varsIgnorePattern: "^[A-Z_]" }],
|
||||||
|
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
|
||||||
|
"react/prop-types": ["off"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import globals from "globals";
|
|
||||||
import pluginJs from "@eslint/js";
|
|
||||||
import tseslint from "typescript-eslint";
|
|
||||||
|
|
||||||
|
|
||||||
/** @type {import('eslint').Linter.Config[]} */
|
|
||||||
export default [
|
|
||||||
{files: ["**/*.{js,mjs,cjs,ts}"]},
|
|
||||||
{languageOptions: { globals: globals.browser }},
|
|
||||||
pluginJs.configs.recommended,
|
|
||||||
...tseslint.configs.recommended,
|
|
||||||
];
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
{
|
|
||||||
"Movies": [
|
|
||||||
{
|
|
||||||
"id": "ebed",
|
|
||||||
"title_id": "ebed",
|
|
||||||
"image_id": "ebed"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "8fd8",
|
|
||||||
"title_id": "8fd8",
|
|
||||||
"image_id": "8fd8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "63cb",
|
|
||||||
"title_id": "63cb",
|
|
||||||
"image_id": "63cb"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Title": [
|
|
||||||
{
|
|
||||||
"id": "ebed",
|
|
||||||
"title": "ФФФФФФФФФфф"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "8fd8",
|
|
||||||
"title": "ittifaq"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "63cb",
|
|
||||||
"title": "priora"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Image": [
|
|
||||||
{
|
|
||||||
"id": "ebed",
|
|
||||||
"imageUrl": "https://avatars.mds.yandex.net/i?id=8e077526d7dfae9d31827e81fea4e74c_l-5233298-images-thumbs&n=13"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "8fd8",
|
|
||||||
"imageUrl": "https://avatars.mds.yandex.net/i?id=17b83f995e81ac7426335d0659a050263d567f34-13135934-images-thumbs&n=13"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "63cb",
|
|
||||||
"imageUrl": "https://ir-3.ozone.ru/s3/multimedia-8/w1200/6738078680.jpg"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Онлайн кинотеатр</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/index.jsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
12
jsconfig.json
Normal file
12
jsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"target": "ES2020",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"baseUrl": "./src/**",
|
||||||
|
"checkJs": true
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "**/node_modules/*"]
|
||||||
|
}
|
||||||
8550
package-lock.json
generated
8550
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
68
package.json
68
package.json
@@ -1,34 +1,38 @@
|
|||||||
{
|
{
|
||||||
"name": "2course-internet-programming",
|
"name": "int-prog",
|
||||||
"version": "1.0.0",
|
"private": true,
|
||||||
"description": "Project of labworks to subject Internet-Programming",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"start": "vite",
|
||||||
"dev": "vite",
|
"vite": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"lint": "eslint src --fix",
|
"serve": "http-server -p 3000 ./dist/",
|
||||||
"format": "prettier --write src/**/*.{js,css,html}",
|
"prod": "npm-run-all build serve",
|
||||||
"preview": "vite preview",
|
"lint": "eslint ."
|
||||||
"backend": "json-server db.json -p 3000"
|
},
|
||||||
},
|
"dependencies": {
|
||||||
|
"bootstrap": "^5.3.5",
|
||||||
"author": "IlyasValiulov",
|
"bootstrap-icons": "^1.11.3",
|
||||||
"license": "ISC",
|
"react": "^19.0.0",
|
||||||
"devDependencies": {
|
"react-dom": "^19.0.0",
|
||||||
"@eslint/js": "^9.22.0",
|
"react-router-dom": "^7.5.1"
|
||||||
"eslint": "^9.22.0",
|
},
|
||||||
"eslint-config-prettier": "^10.1.1",
|
"devDependencies": {
|
||||||
"eslint-plugin-prettier": "^5.2.3",
|
"@eslint/js": "^9.21.0",
|
||||||
"globals": "^16.0.0",
|
"@types/react": "^19.0.10",
|
||||||
"json-server": "^1.0.0-beta.3",
|
"@types/react-dom": "^19.0.4",
|
||||||
"prettier": "^3.5.3",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"sass": "^1.85.1",
|
"eslint": "^9.21.0",
|
||||||
"vite": "^6.2.1"
|
"eslint-config-prettier": "^10.1.1",
|
||||||
},
|
"eslint-import-resolver-vite": "^2.1.0",
|
||||||
|
"eslint-plugin-import": "^2.31.0",
|
||||||
"dependencies": {
|
"eslint-plugin-prettier": "^5.2.5",
|
||||||
"@popperjs/core": "^2.11.8",
|
"eslint-plugin-react": "^7.37.4",
|
||||||
"bootstrap": "^5.3.3"
|
"eslint-plugin-react-hooks": "^5.1.0",
|
||||||
}
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
|
"globals": "^15.15.0",
|
||||||
|
"http-server": "^14.1.1",
|
||||||
|
"vite": "^6.2.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
report.docx
BIN
report.docx
Binary file not shown.
@@ -1,55 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>О нас</title>
|
|
||||||
<script type="module" src="js/main.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<header class="container mt-4 mb-4">
|
|
||||||
<div>
|
|
||||||
<div class="row mb-2 align-items-center">
|
|
||||||
<img src="../images/4k.jpg" id="logo" class="col-auto"/>
|
|
||||||
<h1 class="col display-1">Онлайн кинотеатр</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<nav>
|
|
||||||
<ul class="nav">
|
|
||||||
<li class="nav-item"><a href="index.html" class="nav-link">Главная</a></li>
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a href="catalog.html" class="nav-link dropdown-toggle" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">Фильмы и сериалы</a>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink">
|
|
||||||
<li class="dropdown-item"><a href="catalog.html" class="nav-link">Ужастики</a></li>
|
|
||||||
<li class="dropdown-item"><a href="catalog.html" class="nav-link">Аниме</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item"><a href="about.html" class="nav-link">О нас</a></li>
|
|
||||||
<li class="nav-item"><a href="help.html" class="nav-link">Помощь</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<h2 class="mb-3">Онлайн кинотеатр</h2>
|
|
||||||
<p class="mb-0">Мы рады приветствовать вас на данном сайте</p>
|
|
||||||
<p>
|
|
||||||
Если есть предложения для улучшения работы сайта, пишите на почту
|
|
||||||
<strong><en>ilyasvaliylov@gmail.com</en></strong>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="container mt-auto">
|
|
||||||
<div class="text-center">
|
|
||||||
<p>
|
|
||||||
@ООО ОАО ИП и так далее. Любые лицензии по номеру 78375535378. 4Кйоууу
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
21
src/app/App.jsx
Normal file
21
src/app/App.jsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Route, Routes } from 'react-router-dom';
|
||||||
|
import About from '../pages/About';
|
||||||
|
import Catalog from '../pages/Catalog';
|
||||||
|
import Film from '../pages/Film';
|
||||||
|
import Home from '../pages/Home';
|
||||||
|
import Movies from '../pages/Movies';
|
||||||
|
|
||||||
|
|
||||||
|
export const App = () => {
|
||||||
|
return (
|
||||||
|
<div className="p-2">
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" element={<Home />} />
|
||||||
|
<Route path="/catalog" element={<Catalog />} />
|
||||||
|
<Route path="/about" element={<About />} />
|
||||||
|
<Route path="/film" element={<Film />} />
|
||||||
|
<Route path="movies" element={<Movies />} />
|
||||||
|
</Routes>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
138
src/catalog.html
138
src/catalog.html
@@ -1,138 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Каталог фильмов</title>
|
|
||||||
<script type="module" src="js/main.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<header class="container mt-4 mb-4">
|
|
||||||
<div>
|
|
||||||
<div class="row mb-2 align-items-center">
|
|
||||||
<img src="../images/4k.jpg" id="logo" class="col-auto"/>
|
|
||||||
<h1 class="col display-1">Онлайн кинотеатр</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<nav>
|
|
||||||
<ul class="nav">
|
|
||||||
<li class="nav-item"><a href="index.html" class="nav-link">Главная</a></li>
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a href="catalog.html" class="nav-link dropdown-toggle" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">Фильмы и сериалы</a>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink">
|
|
||||||
<li class="dropdown-item"><a href="catalog.html" class="nav-link">Ужастики</a></li>
|
|
||||||
<li class="dropdown-item"><a href="catalog.html" class="nav-link">Аниме</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item"><a href="about.html" class="nav-link">О нас</a></li>
|
|
||||||
<li class="nav-item"><a href="help.html" class="nav-link">Помощь</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<h2>Каталог фильмов и сериалов</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-md-flex flex-wrap justify-content-between">
|
|
||||||
<div class="w-25 me-3 mb-4">
|
|
||||||
<figure>
|
|
||||||
<figcaption class="mb-2 text-center">
|
|
||||||
<a href="film.html" class="fs-5 link-dark link-underline link-underline-opacity-0">Ловцы забытых голосов (2011)</a>
|
|
||||||
</figcaption>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-3 mb-4">
|
|
||||||
<figure>
|
|
||||||
<figcaption class="mb-2 text-center">
|
|
||||||
<a href="film.html" class="fs-5 link-dark link-underline link-underline-opacity-0">Ловцы забытых голосов (2011)</a>
|
|
||||||
</figcaption>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-3 mb-4">
|
|
||||||
<figure>
|
|
||||||
<figcaption class="mb-2 text-center">
|
|
||||||
<a href="film.html" class="fs-5 link-dark link-underline link-underline-opacity-0">Ловцы забытых голосов (2011)</a>
|
|
||||||
</figcaption>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-3 mb-4">
|
|
||||||
<figure>
|
|
||||||
<figcaption class="mb-2 text-center">
|
|
||||||
<a href="film.html" class="fs-5 link-dark link-underline link-underline-opacity-0">Ловцы забытых голосов (2011)</a>
|
|
||||||
</figcaption>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-3 mb-4">
|
|
||||||
<figure>
|
|
||||||
<figcaption class="mb-2 text-center">
|
|
||||||
<a href="film.html" class="fs-5 link-dark link-underline link-underline-opacity-0">Ловцы забытых голосов (2011)</a>
|
|
||||||
</figcaption>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-3 mb-4">
|
|
||||||
<figure>
|
|
||||||
<figcaption class="mb-2 text-center">
|
|
||||||
<a href="film.html" class="fs-5 link-dark link-underline link-underline-opacity-0">Ловцы забытых голосов (2011)</a>
|
|
||||||
</figcaption>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-3 mb-4">
|
|
||||||
<figure>
|
|
||||||
<figcaption class="mb-2 text-center">
|
|
||||||
<a href="film.html" class="fs-5 link-dark link-underline link-underline-opacity-0">Ловцы забытых голосов (2011)</a>
|
|
||||||
</figcaption>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-3 mb-4">
|
|
||||||
<figure>
|
|
||||||
<figcaption class="mb-2 text-center">
|
|
||||||
<a href="film.html" class="fs-5 link-dark link-underline link-underline-opacity-0">Ловцы забытых голосов (2011)</a>
|
|
||||||
</figcaption>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-3 mb-4">
|
|
||||||
<figure>
|
|
||||||
<figcaption class="mb-2 text-center">
|
|
||||||
<a href="film.html" class="fs-5 link-dark link-underline link-underline-opacity-0">Ловцы забытых голосов (2011)</a>
|
|
||||||
</figcaption>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="container mt-auto">
|
|
||||||
<div class="text-center">
|
|
||||||
<p>
|
|
||||||
@ООО ОАО ИП и так далее. Любые лицензии по номеру 78375535378. 4К
|
|
||||||
йоууу
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
18
src/components/Footer.jsx
Normal file
18
src/components/Footer.jsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export default function Footer() {
|
||||||
|
return (
|
||||||
|
<footer className="container mt-auto">
|
||||||
|
<div className="text-center">
|
||||||
|
<p>
|
||||||
|
@ООО ОАО ИП и так далее. Любые лицензии по номеру 78375535378. 4К йоууу
|
||||||
|
<i className="bi bi-heart ms-2"></i>
|
||||||
|
<i className="bi bi-star-fill ms-1"></i>
|
||||||
|
<i className="bi bi-arrow-right ms-1"></i>
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<i className="bi bi-telegram"> Телеграм</i>
|
||||||
|
<i className="bi bi-discord ms-1"> Дискорд</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
)
|
||||||
|
}
|
||||||
25
src/components/Header.jsx
Normal file
25
src/components/Header.jsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
export default function Header() {
|
||||||
|
return (
|
||||||
|
<header className="container mt-4 mb-4">
|
||||||
|
<div className="row mb-2 align-items-baseline">
|
||||||
|
<img src="/images/4k.jpg" id="logo" className="col-auto" alt="Лого" style={{ width: '200px', height: 'auto' }} />
|
||||||
|
<h1 className="col display-1">Онлайн кинотеатр</h1>
|
||||||
|
</div>
|
||||||
|
<nav>
|
||||||
|
<ul className="nav">
|
||||||
|
<li className="nav-item dropdown">
|
||||||
|
<Link to="/catalog" className="nav-link dropdown-toggle" data-bs-toggle="dropdown"> Фильмы и сериалы </Link>
|
||||||
|
<ul className="dropdown-menu">
|
||||||
|
<li className="dropdown-item"><Link to="/catalog?genre=horror" className="nav-link">Ужастики</Link></li>
|
||||||
|
<li className="dropdown-item"><Link to="/catalog?genre=anime" className="nav-link">Аниме</Link></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li className="nav-item"><Link to="/" className="nav-link">Главная</Link></li>
|
||||||
|
<li className="nav-item"><Link to="/about" className="nav-link">О нас</Link></li>
|
||||||
|
<li className="nav-item"><Link to="/help" className="nav-link">Помощь</Link></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}
|
||||||
19
src/components/MovieCard.jsx
Normal file
19
src/components/MovieCard.jsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
export default function MovieCard({ movie, onEdit, onDelete }) {
|
||||||
|
return (
|
||||||
|
<div className="card h-100">
|
||||||
|
<img src={movie.poster} className="card-img-top" alt={movie.title} />
|
||||||
|
<div className="card-body">
|
||||||
|
<h5 className="card-title">{movie.title}</h5>
|
||||||
|
</div>
|
||||||
|
<div className="card-footer d-flex justify-content-between">
|
||||||
|
<button className="btn btn-sm btn-primary" onClick={onEdit}>
|
||||||
|
Редактировать
|
||||||
|
</button>
|
||||||
|
<button className="btn btn-sm btn-danger" onClick={onDelete}>
|
||||||
|
Удалить
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
57
src/components/MovieForm.jsx
Normal file
57
src/components/MovieForm.jsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
export default function MovieForm({ initialData = {}, onSubmit }) {
|
||||||
|
const [title, setTitle] = useState('')
|
||||||
|
const [poster, setPoster] = useState('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (initialData) {
|
||||||
|
// @ts-ignore
|
||||||
|
setTitle(initialData.title || '')
|
||||||
|
// @ts-ignore
|
||||||
|
setPoster(initialData.poster || '')
|
||||||
|
}
|
||||||
|
}, [initialData])
|
||||||
|
|
||||||
|
const handleSubmit = (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
onSubmit({
|
||||||
|
...initialData,
|
||||||
|
title,
|
||||||
|
poster,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label className="form-label">Название</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control"
|
||||||
|
value={title}
|
||||||
|
onChange={e => setTitle(e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="form-label">URL постера</label>
|
||||||
|
<input
|
||||||
|
type="url"
|
||||||
|
className="form-control"
|
||||||
|
value={poster}
|
||||||
|
onChange={e => setPoster(e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" className="btn btn-primary" >
|
||||||
|
{initialData?.
|
||||||
|
// @ts-ignore
|
||||||
|
id ? 'Сохранить' : 'Добавить'}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ru">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Редактирование фильма</title>
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container mt-4">
|
|
||||||
<h1 class="mb-4" id="formTitle">Добавить новый фильм</h1>
|
|
||||||
|
|
||||||
<form id="movieForm">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="movieTitle" class="form-label">Название фильма</label>
|
|
||||||
<input type="text" class="form-control" id="movieTitle" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="movieImage" class="form-label">Ссылка на изображение</label>
|
|
||||||
<input type="url" class="form-control" id="movieImage" placeholder="https://example.com/image.jpg">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<button type="submit" class="btn btn-primary">Сохранить</button>
|
|
||||||
<a href="help.html" class="btn btn-secondary">Отмена</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- <script src="js/model.js"></script>
|
|
||||||
<script src="js/view.js"></script>
|
|
||||||
<script src="js/controller.js"></script> -->
|
|
||||||
<script type="module" src="js/main.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Film</title>
|
|
||||||
<script type="module" src="js/main.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header class="container mt-4 mb-4">
|
|
||||||
<div>
|
|
||||||
<div class="row mb-2 align-items-center">
|
|
||||||
<img src="../images/4k.jpg" id="logo" class="col-auto"/>
|
|
||||||
<h1 class="col display-1">Онлайн кинотеатр</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<nav>
|
|
||||||
<ul class="nav">
|
|
||||||
<li class="nav-item"><a href="index.html" class="nav-link">Главная</a></li>
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a href="catalog.html" class="nav-link dropdown-toggle" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">Фильмы и сериалы</a>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink">
|
|
||||||
<li class="dropdown-item"><a href="catalog.html" class="nav-link">Ужастики</a></li>
|
|
||||||
<li class="dropdown-item"><a href="catalog.html" class="nav-link">Аниме</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item"><a href="about.html" class="nav-link">О нас</a></li>
|
|
||||||
<li class="nav-item"><a href="help.html" class="nav-link">Помощь</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<div class="film">
|
|
||||||
<h2 class="card-title mb-4">Ловцы забытых голосов (2011)</h2>
|
|
||||||
<p class="card-text mb-4">
|
|
||||||
Юная Асуна живет с вечно пропадающей на работе матерью и после школы
|
|
||||||
любит забираться на скалу, чтобы послушать радио, доставшееся от
|
|
||||||
умершего отца. Однажды в этом своем секретном месте она знакомится с
|
|
||||||
загадочным юношей Сюном, который говорит, что пришел из далекой страны
|
|
||||||
Агартхи. Эта встреча становится началом полного приключений
|
|
||||||
путешествия в волшебный мир, где Асуне предстоит столкнуться с
|
|
||||||
потерями и обрести надежду.
|
|
||||||
</p>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid w-25 ms-4 mb-4" />
|
|
||||||
<ul class="film-container">
|
|
||||||
<li>Год производства 2011</li>
|
|
||||||
<hr />
|
|
||||||
<li>Жанр аниме, мультфильм, драма, приключения</li>
|
|
||||||
<hr />
|
|
||||||
<li>Режиссер Макото Синкай</li>
|
|
||||||
<hr />
|
|
||||||
<li>Сборы в мире $600 486</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
<a href="https://www.kinopoisk.ru/film/581102/">Смотреть фильм</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="container mt-auto">
|
|
||||||
<div class="text-center">
|
|
||||||
<p>
|
|
||||||
@ООО ОАО ИП и так далее. Любые лицензии по номеру 78375535378. 4К йоууу
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
108
src/help.html
108
src/help.html
@@ -1,108 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Помощь</title>
|
|
||||||
<!-- <link rel="stylesheet" href="css/style.css" />
|
|
||||||
<link rel="stylesheet" href="npcss/help.css" /> -->
|
|
||||||
<!-- <script type="module" src="js/main.js"></script> -->
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header class="container mt-4 mb-4">
|
|
||||||
<div>
|
|
||||||
<div class="row mb-2 align-items-center">
|
|
||||||
<img src="../images/4k.jpg" id="logo" class="col-auto"/>
|
|
||||||
<h1 class="col display-1">Онлайн кинотеатр</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<nav>
|
|
||||||
<ul class="nav">
|
|
||||||
<li class="nav-item"><a href="index.html" class="nav-link">Главная</a></li>
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a href="catalog.html" class="nav-link dropdown-toggle" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">Фильмы и сериалы</a>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink">
|
|
||||||
<li class="dropdown-item"><a href="catalog.html" class="nav-link">Ужастики</a></li>
|
|
||||||
<li class="dropdown-item"><a href="catalog.html" class="nav-link">Аниме</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item"><a href="about.html" class="nav-link">О нас</a></li>
|
|
||||||
<li class="nav-item"><a href="help.html" class="nav-link">Помощь</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- <div class="container">
|
|
||||||
<h2>Добавить фильм</h2>
|
|
||||||
<p></p>
|
|
||||||
|
|
||||||
<form id="movieForm">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="movieTitle" class="form-label">Название фильма</label>
|
|
||||||
<input type="text" class="form-control" id="movieTitle" placeholder="Введите название фильма" required>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="movieImage" class="form-label">Загрузите изображение</label>
|
|
||||||
<input type="file" class="form-control" id="movieImage" accept="image/*" required>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary">Добавить фильм</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div id="movieContainer" class="row mt-5"></div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div class="container mt-4">
|
|
||||||
<h1 class="mb-4">Мои фильмы</h1>
|
|
||||||
|
|
||||||
<div class="mb-4">
|
|
||||||
<a href="edit.html" class="btn btn-success">Добавить новый фильм</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="movieContainer" class="row"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="container mt-auto">
|
|
||||||
<div class="text-center">
|
|
||||||
<p>
|
|
||||||
@ООО ОАО ИП и так далее. Любые лицензии по номеру 78375535378. 4Кйоууу
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
|
|
||||||
<!-- <script src="js/model.js"></script>
|
|
||||||
<script src="js/view.js"></script>
|
|
||||||
<script src="js/controller.js"></script> -->
|
|
||||||
<script type="module" src="js/main.js"></script>
|
|
||||||
|
|
||||||
<!-- <script>
|
|
||||||
document.getElementById('movieForm').addEventListener('submit', function (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
const title = document.getElementById('movieTitle').value;
|
|
||||||
const imageFile = document.getElementById('movieImage').files[0];
|
|
||||||
|
|
||||||
const card = document.createElement('div');
|
|
||||||
card.className = 'col-md-4';
|
|
||||||
|
|
||||||
const cardInner = `
|
|
||||||
<div class="card">
|
|
||||||
<img src="${URL.createObjectURL(imageFile)}" class="card-img-top" alt="${title}">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title">${title}</h5>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
card.innerHTML = cardInner;
|
|
||||||
|
|
||||||
document.getElementById('movieContainer').appendChild(card);
|
|
||||||
|
|
||||||
document.getElementById('movieForm').reset();
|
|
||||||
});
|
|
||||||
</script> -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
104
src/index.html
104
src/index.html
@@ -1,104 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Онлайн кинотеатр</title>
|
|
||||||
<script type="module" src="js/main.js"></script>
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<header class="container mt-4 mb-4">
|
|
||||||
<div>
|
|
||||||
<div class="row mb-2 align-items-center">
|
|
||||||
<img src="../images/4k.jpg" id="logo" class="col-auto"/>
|
|
||||||
<h1 class="col display-1">Онлайн кинотеатр</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<nav>
|
|
||||||
<ul class="nav">
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a href="catalog.html" class="nav-link dropdown-toggle" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">Фильмы и сериалы</a>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink">
|
|
||||||
<li class="dropdown-item"><a href="catalog.html" class="nav-link">Ужастики</a></li>
|
|
||||||
<li class="dropdown-item"><a href="catalog.html" class="nav-link">Аниме</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item"><a href="about.html" class="nav-link">О нас</a></li>
|
|
||||||
<li class="nav-item"><a href="help.html" class="nav-link">Помощь</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<div>
|
|
||||||
<h2>Добро пожаловать в онлайн кинотеатр</h2>
|
|
||||||
<p>Смотрите фильмы бесплатно и без ограничений.</p>
|
|
||||||
<h2>Премьеры недели</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-md-flex flex-wrap justify-content-between">
|
|
||||||
<div class="w-25 me-3">
|
|
||||||
<h4>Ловцы забытых голосов</h4>
|
|
||||||
<figure>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
<figcaption>
|
|
||||||
<a href="film.html" target="_blank">Смотреть</a>
|
|
||||||
</figcaption>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-3">
|
|
||||||
<h4>Ловцы забытых голосов</h4>
|
|
||||||
<figure>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
<figcaption>
|
|
||||||
<a href="film.html" target="_blank">Смотреть</a>
|
|
||||||
</figcaption>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-3">
|
|
||||||
<h4>Ловцы забытых голосов</h4>
|
|
||||||
<figure>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
<figcaption>
|
|
||||||
<a href="film.html" target="_blank">Смотреть</a>
|
|
||||||
</figcaption>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-25 me-auto">
|
|
||||||
<h4>Ловцы забытых голосов</h4>
|
|
||||||
<figure>
|
|
||||||
<img src="../images/film.jpg" class="img-fluid"/>
|
|
||||||
<figcaption>
|
|
||||||
<a href="film.html" target="_blank">Смотреть</a>
|
|
||||||
</figcaption>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="container mt-auto">
|
|
||||||
<div class="text-center">
|
|
||||||
<p>
|
|
||||||
@ООО ОАО ИП и так далее. Любые лицензии по номеру 78375535378. 4К йоууу
|
|
||||||
<i class="bi bi-heart"></i>
|
|
||||||
<i class="bi bi-star-fill"></i>
|
|
||||||
<i class="bi bi-arrow-right"></i>
|
|
||||||
</p>
|
|
||||||
<div>
|
|
||||||
<i class="bi bi-telegram">Телеграмм</i>
|
|
||||||
<i class="bi bi-discord ms-1">Дискорд</i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
15
src/index.jsx
Normal file
15
src/index.jsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
|
import { App } from "./app/App";
|
||||||
|
|
||||||
|
import 'bootstrap-icons/font/bootstrap-icons.css';
|
||||||
|
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||||
|
|
||||||
|
createRoot(document.getElementById("root")).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<BrowserRouter>
|
||||||
|
<App />
|
||||||
|
</BrowserRouter>
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
export class MovieController {
|
|
||||||
|
|
||||||
constructor(model, view) {
|
|
||||||
this.model = model;
|
|
||||||
this.view = view;
|
|
||||||
this.currentMovieId = null;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
|
||||||
this.currentMovieId = urlParams.get('id');
|
|
||||||
|
|
||||||
if (window.location.pathname.includes('edit.html')) {
|
|
||||||
await this.initEditPage();
|
|
||||||
} else {
|
|
||||||
await this.initListPage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async initListPage() {
|
|
||||||
const movies = await this.model.fetchMovies();
|
|
||||||
this.view.renderMovies(movies);
|
|
||||||
|
|
||||||
this.view.movieContainer.addEventListener('click', async (e) => {
|
|
||||||
if (e.target.classList.contains('delete-btn')) {
|
|
||||||
const id = e.target.getAttribute('data-id');
|
|
||||||
const confirmed = confirm('Вы уверены, что хотите удалить этот фильм?');
|
|
||||||
|
|
||||||
if (confirmed) {
|
|
||||||
const success = await this.model.deleteMovie(id);
|
|
||||||
if (success) {
|
|
||||||
const movies = await this.model.fetchMovies();
|
|
||||||
this.view.renderMovies(movies);
|
|
||||||
} else {
|
|
||||||
this.view.showError('Не удалось удалить фильм');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async initEditPage() {
|
|
||||||
if (this.currentMovieId) {
|
|
||||||
const movie = await this.model.getMovieById(this.currentMovieId);
|
|
||||||
if (movie) {
|
|
||||||
this.view.fillFormWithMovieData(movie);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.view.movieForm.addEventListener('submit', async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
await this.handleFormSubmit();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleFormSubmit() {
|
|
||||||
const movieData = this.view.getFormData();
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (this.currentMovieId) {
|
|
||||||
const updatedMovie = await this.model.updateMovie(this.currentMovieId, movieData);
|
|
||||||
if (updatedMovie) {
|
|
||||||
this.view.redirectToList();
|
|
||||||
} else {
|
|
||||||
this.view.showError('Не удалось обновить фильм');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const newMovie = await this.model.createMovie(movieData);
|
|
||||||
if (newMovie) {
|
|
||||||
this.view.redirectToList();
|
|
||||||
} else {
|
|
||||||
this.view.showError('Не удалось создать фильм');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
this.view.showError('Произошла ошибка при сохранении фильма');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import '../scss/styles.scss';
|
|
||||||
|
|
||||||
import { MovieModel } from './model.js';
|
|
||||||
import { MovieView } from './view.js';
|
|
||||||
import { MovieController } from './controller.js';
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const model = new MovieModel();
|
|
||||||
const view = new MovieView();
|
|
||||||
const controller = new MovieController(model, view);
|
|
||||||
});
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
export class MovieModel {
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.apiUrl = 'http://localhost:3000/movies';
|
|
||||||
}
|
|
||||||
|
|
||||||
async getMovieById(id) {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${this.apiUrl}/${id}`);
|
|
||||||
return await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching movie:', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchMovies() {
|
|
||||||
try {
|
|
||||||
const response = await fetch(this.apiUrl);
|
|
||||||
return await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching movies:', error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async createMovie(movieData) {
|
|
||||||
try {
|
|
||||||
const response = await fetch(this.apiUrl, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(movieData),
|
|
||||||
});
|
|
||||||
return await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error creating movie:', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateMovie(id, movieData) {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${this.apiUrl}/${id}`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(movieData),
|
|
||||||
});
|
|
||||||
return await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error updating movie:', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteMovie(id) {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${this.apiUrl}/${id}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
});
|
|
||||||
return response.ok;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error deleting movie:', error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
export class MovieView {
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.movieContainer = document.getElementById('movieContainer');
|
|
||||||
this.movieForm = document.getElementById('movieForm');
|
|
||||||
}
|
|
||||||
|
|
||||||
renderMovies(movies) {
|
|
||||||
this.movieContainer.innerHTML = '';
|
|
||||||
|
|
||||||
movies.forEach(movie => {
|
|
||||||
const card = document.createElement('div');
|
|
||||||
card.className = 'col-md-4 mb-4';
|
|
||||||
|
|
||||||
const cardInner = `
|
|
||||||
<div class="card">
|
|
||||||
<img src="${movie.imageUrl || 'https://via.placeholder.com/300x450'}" class="card-img-top" alt="${movie.title}">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title">${movie.title}</h5>
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<a href="edit.html?id=${movie.id}" class="btn btn-warning">Редактировать</a>
|
|
||||||
<button class="btn btn-danger delete-btn" data-id="${movie.id}">Удалить</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
card.innerHTML = cardInner;
|
|
||||||
this.movieContainer.appendChild(card);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fillFormWithMovieData(movie) {
|
|
||||||
document.getElementById('movieTitle').value = movie.title;
|
|
||||||
document.getElementById('movieImage').value = movie.imageUrl || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
getFormData() {
|
|
||||||
return {
|
|
||||||
title: document.getElementById('movieTitle').value,
|
|
||||||
imageUrl: document.getElementById('movieImage').value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
showError(message) {
|
|
||||||
alert(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
redirectToList() {
|
|
||||||
window.location.href = 'help.html';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
25
src/pages/About.jsx
Normal file
25
src/pages/About.jsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import Footer from '../components/Footer'
|
||||||
|
import Header from '../components/Header'
|
||||||
|
|
||||||
|
export default function About() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
|
||||||
|
<div className="container">
|
||||||
|
<h2 className="mb-3">О нас</h2>
|
||||||
|
<p className="mb-0">
|
||||||
|
Мы рады приветствовать вас на данном сайте.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Если есть предложения для улучшения работы сайта, пишите на почту
|
||||||
|
<a href="mailto:ilyasvaliylov@gmail.com">
|
||||||
|
ilyasvaliylov@gmail.com
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
28
src/pages/Catalog.jsx
Normal file
28
src/pages/Catalog.jsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import Footer from '../components/Footer'
|
||||||
|
import Header from '../components/Header'
|
||||||
|
|
||||||
|
export default function Catalog() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<div className="container mb-4">
|
||||||
|
<h2>Каталог фильмов и сериалов</h2>
|
||||||
|
<div className="d-md-flex flex-wrap justify-content-between">
|
||||||
|
{Array.from({ length: 9 }).map((_, i) => (
|
||||||
|
<div key={i} className="w-25 me-3 mb-4 text-center">
|
||||||
|
<figure>
|
||||||
|
<figcaption className="mb-2">
|
||||||
|
<a href="/film" className="fs-5 link-dark text-decoration-none">
|
||||||
|
Ловцы забытых голосов (2011)
|
||||||
|
</a>
|
||||||
|
</figcaption>
|
||||||
|
<img src="/images/film.jpg" className="img-fluid" alt="Постер" />
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
43
src/pages/Film.jsx
Normal file
43
src/pages/Film.jsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import Footer from '../components/Footer'
|
||||||
|
import Header from '../components/Header'
|
||||||
|
|
||||||
|
export default function Film() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
|
||||||
|
<div className="container">
|
||||||
|
<div className="film">
|
||||||
|
<h2 className="card-title mb-4">Ловцы забытых голосов (2011)</h2>
|
||||||
|
|
||||||
|
<p className="card-text mb-4">
|
||||||
|
Юная Асуна живет с вечно пропадающей на работе матерью и после школы
|
||||||
|
любит забираться на скалу, чтобы послушать радио, доставшееся от
|
||||||
|
умершего отца. Однажды в этом своем секретном месте она знакомится с
|
||||||
|
загадочным юношей Сюном, который говорит, что пришел из далекой страны
|
||||||
|
Агартхи. Эта встреча становится началом полного приключений
|
||||||
|
путешествия в волшебный мир, где Асуне предстоит столкнуться с
|
||||||
|
потерями и обрести надежду.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<img src="/images/film.jpg" className="img-fluid w-25 me-4 mb-4" alt="Постер фильма" />
|
||||||
|
|
||||||
|
<ul className="list-unstyled film-container mb-4">
|
||||||
|
<li><strong>Год производства:</strong> 2011</li>
|
||||||
|
<li><strong>Жанр:</strong> аниме, мультфильм, драма, приключения</li>
|
||||||
|
<li><strong>Режиссер:</strong> Макото Синкай</li>
|
||||||
|
<li><strong>Сборы в мире:</strong> $600 486</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="https://www.kinopoisk.ru/film/581102/" target="_blank" rel="noopener noreferrer">
|
||||||
|
Смотреть фильм на КиноПоиск
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
29
src/pages/Home.jsx
Normal file
29
src/pages/Home.jsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import Footer from '../components/Footer'
|
||||||
|
import Header from '../components/Header'
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<div className="container">
|
||||||
|
<h2>Добро пожаловать в онлайн кинотеатр</h2>
|
||||||
|
<p>Смотрите фильмы бесплатно и без ограничений.</p>
|
||||||
|
<h2>Премьеры недели</h2>
|
||||||
|
<div className="d-md-flex flex-wrap justify-content-between">
|
||||||
|
{Array.from({ length: 4 }).map((_, i) => (
|
||||||
|
<div key={i} className="w-25 me-3 mb-4">
|
||||||
|
<h4>Ловцы забытых голосов</h4>
|
||||||
|
<figure>
|
||||||
|
<img src="/images/film.jpg" className="img-fluid" alt="Постер" />
|
||||||
|
<figcaption>
|
||||||
|
<a href="/film" target="_blank" rel="noopener noreferrer">Смотреть</a>
|
||||||
|
</figcaption>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
96
src/pages/Movies.jsx
Normal file
96
src/pages/Movies.jsx
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import Footer from '../components/Footer'
|
||||||
|
import Header from '../components/Header'
|
||||||
|
import MovieCard from '../components/MovieCard'
|
||||||
|
import MovieForm from '../components/MovieForm'
|
||||||
|
|
||||||
|
export default function Movies() {
|
||||||
|
const [movies, setMovies] = useState([])
|
||||||
|
const [showForm, setShowForm] = useState(false)
|
||||||
|
const [editingMovie, setEditing] = useState(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('http://localhost:3001/movies')
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => setMovies(data))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
setEditing(null)
|
||||||
|
setShowForm(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEdit = (movie) => {
|
||||||
|
setEditing(movie)
|
||||||
|
setShowForm(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = (id) => {
|
||||||
|
fetch(`http://localhost:3001/movies/${id}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
}).then(() => {
|
||||||
|
setMovies(prev => prev.filter(m => m.id !== id))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = (movieData) => {
|
||||||
|
if (editingMovie) {
|
||||||
|
fetch(`http://localhost:3001/movies/${movieData.id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(movieData),
|
||||||
|
}).then(() => {
|
||||||
|
setMovies(prev => prev.map(m => m.id === movieData.id ? movieData : m))
|
||||||
|
setShowForm(false)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
fetch('http://localhost:3001/movies', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(movieData),
|
||||||
|
})
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(newMovie => {
|
||||||
|
setMovies(prev => [...prev, newMovie])
|
||||||
|
setShowForm(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<div className="container mt-4">
|
||||||
|
<h1 className="mb-4">Мои фильмы</h1>
|
||||||
|
<button className="btn btn-success mb-4" onClick={handleAdd}>
|
||||||
|
Добавить новый фильм
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{showForm && (
|
||||||
|
<MovieForm
|
||||||
|
initialData={editingMovie}
|
||||||
|
onCancel={() => setShowForm(false)}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
{movies.map(movie => (
|
||||||
|
<div key={movie.id} className="col-md-4 mb-4">
|
||||||
|
<MovieCard
|
||||||
|
movie={movie}
|
||||||
|
onEdit={() => handleEdit(movie)}
|
||||||
|
onDelete={() => handleDelete(movie.id)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
@import "../../node_modules/bootstrap/scss/bootstrap";
|
|
||||||
|
|
||||||
#logo {
|
|
||||||
width: 150px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,25 +1,6 @@
|
|||||||
import { defineConfig } from 'vite';
|
import react from "@vitejs/plugin-react";
|
||||||
import path from 'path';
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
build: {
|
plugins: [react()],
|
||||||
rollupOptions: {
|
|
||||||
input: {
|
|
||||||
main: path.resolve(__dirname, 'index.html'),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// server: {
|
|
||||||
// port: 3000,
|
|
||||||
// hot: true,
|
|
||||||
// },
|
|
||||||
server: {
|
|
||||||
proxy: {
|
|
||||||
'/api': {
|
|
||||||
target: 'http://localhost:3000',
|
|
||||||
changeOrigin: true,
|
|
||||||
rewrite: (path) => path.replace(/^\/api/, '')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user