This commit is contained in:
ValAnn 2023-11-16 13:21:52 +04:00
parent 5b3cf71a64
commit ec23101d55
134 changed files with 28941 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,18 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}

24
3_Lab/testBootstrap_main/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -0,0 +1,56 @@
<div class="input-group quantity-goods">
<input type="button" value="-" id="button_minus">
<input type="number" step="1" min="1" max="10" id="num_count" name="quantity" value="1" title="Qty">
<input type="button" value="+" id="button_plus">
</div>
<div class="panel-col col-md-3 col-12 d-flex align-items-stretch pb-4">
<div class="row justify-content-center">
<div class="col-md-12 col-4 align-self-center ">
<div class="banner-main pt-2 pb-2">
<div class="row ">
<div class="col-7">
<p class="banner-text ms-2">Топ-10 книг для осени</p>
</div>
<div class="col-5">
<img src="/icons_main/free-icon-magic-book-867810 1.png" alt="" width="80%">
</div>
</div>
</div>
<div class="col-md-12 col-4 align-self-center">
<div class="banner-main pt-2 pb-2">
<div class="row ">
<div class="col-7">
<p class="banner-text ms-2">Выставка книг о японской культуре в эти выходные</p>
</div>
<div class="col-5">
<img src="/icons_main/free-icon-japan-6259275 1.png" alt="" width="80%">
</div>
</div>
</div>
<div class="col-md-12 col-4 d-flex align-self-center">
<div class="banner-main pt-2 pb-2">
<div class="row ">
<div class="col-7">
<p class="banner-text ms-2">Эксклюзивно в БукКэмп Невозможно пропстить</p>
</div>
<div class="col-5">
<img src="/icons_main/image1book.png" alt="" width="80%">
</div>
</div>
</div>
</div>
</div>
</section>
</div>

View File

@ -0,0 +1,27 @@
# React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
- Configure the top-level `parserOptions` property like this:
```js
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json'],
tsconfigRootDir: __dirname,
},
```
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list

View File

@ -0,0 +1,19 @@
// let res = document.getElementById('num_count')
// const plusButton = document.getElementById('button_plus')
// const minusButton = document.getElementById('button_minus')
// plusButton.onclick = function () {
// res.value = Number(res.value) + Number(1)
// }
// minusButton.onclick = function () {
// if (Number(res.value) > 1){
// res.value = Number(res.value) - Number(1)
// }
// }
// HTMLDataListElement.onclick = function(event){
// console.log(event.target)
// }

View File

@ -0,0 +1,26 @@
#banner{
display: flex;
}
#banner a img.banner-show {
height: auto;
width: auto;
justify-content: center;
}
#banner a img.banner-hide {
height: 0;
width: 0;
opacity: 0;
visibility: hidden;
transition: opacity 1s, visibility 0s 1s;
display: none;
}
#banner > a{
display: block;
}

View File

@ -0,0 +1,45 @@
// модуль для смены изображения в баннере по таймеру
import "./banner.css";
// указывается блок, в котором будет баннер
// блок должен содержать изображения
function myBanner(root) {
console.info("Loaded");
const banners = document.querySelectorAll("#banner > a > img"); //a > img.button-sm
for (let i = 0; i < banners.length; i += 1) {
banners[i].setAttribute("class", "banner-hide");
}
let old = banners.length - 1;
let current = 0;
// функция меняет изображения в цикле
// изображение с классом banner-show будет показано
// изображение с классом banner-hide будет скрыто
// функция запускает таймер, который через 5 секунд
// запускает функцию, снова создается таймер и т. д.
function loop() {
banners[current].setAttribute("class", "banner-show button-sm m-2 img-fluid ");
banners[old].setAttribute("class", "banner-hide m-2");
console.info("Banner changed");
old = current;
current += 1;
if (current === banners.length) {
current = 0;
}
setTimeout(loop, 5000);
}
loop();
}
export default myBanner;

View File

@ -0,0 +1,19 @@
{
"posts": [
{
"id": 1,
"title": "json-server",
"author": "typicode"
}
],
"comments": [
{
"id": 1,
"body": "some comment",
"postId": 1
}
],
"profile": {
"name": "typicode"
}
}

File diff suppressed because one or more lines are too long

62
3_Lab/testBootstrap_main/fontello.css vendored Normal file
View File

@ -0,0 +1,62 @@
@font-face {
font-family: 'fontello';
src: url('../font/fontello.eot?88763656');
src: url('../font/fontello.eot?88763656#iefix') format('embedded-opentype'),
url('../font/fontello.woff2?88763656') format('woff2'),
url('../font/fontello.woff?88763656') format('woff'),
url('../font/fontello.ttf?88763656') format('truetype'),
url('../font/fontello.svg?88763656#fontello') format('svg');
font-weight: normal;
font-style: normal;
}
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
/*
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'fontello';
src: url('../font/fontello.svg?88763656#fontello') format('svg');
}
}
*/
[class^="icon-"]:before, [class*=" icon-"]:before {
font-family: "fontello";
font-style: normal;
font-weight: normal;
speak: never;
display: inline-block;
text-decoration: inherit;
width: 1em;
margin-right: .2em;
text-align: center;
/* opacity: .8; */
/* For safety - reset parent styles, that can break glyph codes*/
font-variant: normal;
text-transform: none;
/* fix buttons height, for twitter bootstrap */
line-height: 1em;
/* Animation center compensation - margins should be symmetric */
/* remove if not needed */
margin-left: .2em;
/* you can be more comfortable with increased icons size */
/* font-size: 120%; */
/* Font smoothing. That was taken from TWBS */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Uncomment for 3D effect */
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
}
.icon-heart-empty:before { content: '\e800'; } /* '' */
.icon-mail-alt:before { content: '\f0e0'; } /* '' */
.icon-anchor:before { content: '\f13d'; } /* '' */
.icon-compass:before { content: '\f14e'; } /* '' */
.icon-female:before { content: '\f182'; } /* '' */
.icon-safari:before { content: '\f267'; } /* '' */

View File

@ -0,0 +1,149 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Главная страница</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
<script src="/node_modules/bootstrap/dist/js/bootstrap.js"></script>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="/fontello.css" type="text/css" />
<link rel="stylesheet" href="style.css">
<script src="app.js"></script>
</head>
<body class="d-flex flex-column min-vh-100">
<header>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<img src="/src/logoOfLibrary.png" alt="" width="80" class="d-inline-block align-text-top" border-radius="20%">
</a>
<a class="about-us-link nav-link link-light fs-5" href="/pageAboutUs.html">О нас</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="navbar-collapse collapse justify-content-end p-3 bg-dark" id="navbarNav">
<div class="navbar-nav p-3">
<a class="nav-link fs-5 text-light " href="./pageCatalog.html">Каталог</a>
<a class="nav-link fs-5 text-light " href="./pageBasket.html">Корзина</a>
</div>
<section class="menu align-self-center">
<a class="nav-link text-end fs-5 lh-2 text-light" href="./pageSignUp.html">Зарегистрироваться</a>
<a class="nav-link text-end fs-6 text-light" href="./pageSignIn.html">Уже есть аккаунт?</a>
</section>
</div>
</div>
</nav>
</header>
<main class="container-fluid p-2">
<div class="row justify-content-center">
<div class="first-col col-md-6 mb-1">
<div id="banner" class="banner-class">
<a href="/pageOfBook1.html" ><img src="src/banners/big_banners/main-banner.png" class="banner-hide button-sm m-2 img-fluid" alt="" ></a>
<a href="/pageOfBook1.html" ><img src="src/banners/big_banners/main-banner_2.png" class="banner-hide button-sm m-2 img-fluid" alt="" ></a>
</div>
</div>
<div class="panel-col col-md-4 pb-4 ps-4">
<div class="banner-main pt-2 pb-2">
<div class="row ">
<div class="col-md-7">
<p class="banner-text ms-2">Топ-10 книг для осени</p>
</div>
<div class="col-5">
<img src="src/icons/icons_main/free-icon-magic-book-867810 1.png" class="d-none d-md-block" alt="" width="50%">
</div>
</div>
</div>
<div class="banner-main pt-2 pb-2">
<div class="row ">
<div class="col-md-7">
<p class="banner-text ms-2">Выставка книг о японской культуре в эти выходные</p>
</div>
<div class="col-5">
<img src="src/icons/icons_main/free-icon-japan-6259275 1.png" class="d-none d-md-block" alt="" width="50%">
</div>
</div>
</div>
<div class="banner-main pt-2 pb-2">
<div class="row ">
<div class="col-md-7">
<p class="banner-text ms-2">Эксклюзивно в БукКэмп Невозможно пропстить</p>
</div>
<div class="col-5">
<img src="src/icons/icons_main/image1book.png" alt="" class="d-none d-md-block" width="50%">
</div>
</div>
</div>
</div>
</section>
</div>
<div class="conteiner ms-4">
<h3>Последние поступления</h3>
<div class="row justify-content-md-start justify-content-center">
<div class="col-md-2 col-4 mt-3" action="./page3.html" method="get">
<a href="/pageOfBook1.html" ><img src="/src/covers/image1book.png" class="button-sm" alt="" width="100%"></a>
</div>
<div class="col-md-2 col-4 m-3" action="./page3.html" method="get">
<a href="/pageOfBook1.html" ><img src="/src/covers/image2book.png" class="button-sm" alt="" width="100%"></a>
</div>
</div>
</div>
</main>
<footer class="footer mt-auto d-flex flex-shrink-0 align-items-center">
<h3 class="ps-0 me-2">Наши соцсети</h3>
<div class="group-sites" role="group">
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-facebook.png" class="button-sm m-auto " alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-viber.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-tg.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-whats-up.png" class="button-sm m-auto" alt="" width="35" ></a>
</div>
</footer>
<script type="module">
import myBanner from "./banner";
document.addEventListener('DOMContentLoaded', () => {
myBanner("#banner");
});
</script>
</body>
</html>

View File

@ -0,0 +1,26 @@
{
"items":[
{
"id":1,
"name":"Ведьмак. Последнее желание",
"autor":"Анджей Сапковский",
"info":"info",
"annotation":"annotation"
},
{
"id":2,
"name":"Ведьмак. Меч предназначения",
"autor":"Анджей Сапковский",
"info":"info",
"annotation":"annotation"
},
{
"id":1,
"name":"Ведьмак. Кровь эльфов",
"autor":"Анджей Сапковский",
"info":"info",
"annotation":"annotation"
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4494
3_Lab/testBootstrap_main/js/bootstrap.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,95 @@
// модуль с логикой
import {
getAllLines
} from "./lines-rest-api";
import rememberIdOfBook from "./page"
export const cntrls = {
button: document.getElementById("items-add"),
table: document.getElementById("body"),
form: document.getElementById("items-form"),
id: document.getElementById("id"),
name: document.getElementById("name-book"),
autor: document.getElementById("autor"),
annotation: document.getElementById("annotation"),
info: document.getElementById("info")
};
export async function drawCardsCatalog(){
console.info("Try to load data");
const data = await getAllLines();
let catalog = document.getElementById("catalog")
catalog.innerHTML = "";
let catalogHTML = ""
console.log(data)
data.forEach((item, index) => {
console.log(index)
catalogHTML +=
createCard(
item,
index,
)
});
catalogHTML += `<div class="row justify-content-evenly mt-4">
<div class="col-md-3 col-6 align-self-end col-bott">
<div class="card" style="width: 100%;">
<a href="/pageAdmin.html"> <img src="/src/covers/addbook1.png" class="card-img-top" alt="..." ></a>
<div class="card-body">
<p class="card-title mt-0 mb-0">???</p>
<p class="card-text">?????</p>
<a href="#" class="btn btn-catalog btn-primary rounded-0 mt-1 border ">Добавить книгу</a>
</div>
</div>
</div>
</div>`
catalog.innerHTML = catalogHTML
console.log(catalogHTML)
}
export function createCard(item, index) {
let card = `
<div class="col-md-3 col-6 mb-sm-0 align-self-end ">
<div class="card" style="width: 100%;">
<a href="/pageOfBook1.html"> <img src="/src/covers/image${item.id}book.png" class="card-img-top" alt="..." lowsrc=></a>
<div class="card-body">
<p class="card-title mt-0 mb-0">${item.name}</p>
<p class="card-text ">${item.autor}</p>
<a href="/pageOfBook1.html"><div class="btn btn-catalog btn-primary rounded-0 mt-1 border" onclick="rememberId(${item.id});" >Добавить в корзину</div></a>
</div>
</div>
</div>
`
if ((index)% 3 == 0){
card = `<div class="row justify-content-evenly mt-4">
` + card
}
if (Number(index - 2) % 3 == 0){
card += `</div>
`
}
return card;
}
let tempId = 0
export function rememberId(id){
rememberIdOfBook(id)
console.log("F")
}
export default drawCardsCatalog

View File

@ -0,0 +1,2 @@

View File

@ -0,0 +1,65 @@
// Модуль для работы с модальным окном
// импорт компонента Modal из bootstrap
import { Modal } from "bootstrap";
import { cntrls, imagePlaceholder } from "./lines-ui";
// поиск модального окна на странице
const modal = document.getElementById("items-update");
// если он найден, то создается экземпляр компонента Modal
// для программного управления модальным окном
const myModal = modal ? new Modal(modal, {}) : null;
// поиск тега с заголовком модального кона для его смены
const modalTitle = document.getElementById("items-update-title");
// обнуление значений модального окна, т. к.
// используется одно окно для всех операций
function resetValues() {
cntrls.id.value = "";
cntrls.name.value = "";
cntrls.autor.value = "";
cntrls.info.value = "";
cntrls.annotation.value = "";
cntrls.number.value = "";
cntrls.image.value = "";
cntrls.imagePreview.src = imagePlaceholder;
}
// функция для показа модального окна
// перед показом происходит заполнение формы для редактирования
// если объект item не пуст
export function showUpdateModal(item) {
modalTitle.innerHTML = item === null ? "Добавить" : "Изменить";
console.info(item);
if (item) {
cntrls.id.value = item.id;
cntrls.name.value = item.name,
cntrls.annotation.value = item.annotation;
cntrls.info.value = item.info;
cntrls.autor.value = item.autor;
cntrls.number.value = item.number;
cntrls.image.src = item.cover;
// заполнение превью
// Если пользователь выбрал изображение, то оно загружается
// в тэг image с id image - preview
// иначе устанавливается заглушка, адрес которой указан в imagePlaceholder
cntrls.imagePreview.src = item.image ? item.image : imagePlaceholder;
} else {
resetValues();
}
myModal.show();
}
// функция для скрытия модального окна
export function hideUpdateModal() {
resetValues();
// удаление класса was-validated для скрытия результатов валидации
cntrls.form.classList.remove("was-validated");
myModal.hide();
}

View File

@ -0,0 +1,103 @@
// модуль для работы с REST API сервера
// адрес сервера
const serverUrl = "http://localhost:8081";
// функция возвращает объект нужной структуры для отправки на сервер
function createLineObject(id, name, autor, number, annotation, info, image) {
return {
id : id,
name : name,
autor: autor,
info: info,
annotation: annotation,
number: number,
cover: image
};
}// модуль для работы с REST API сервера
// обращение к серверу для получения всех типов товара (get)
export async function getAllItemTypes() {
const response = await fetch(`${serverUrl}/items/`);
if (!response.ok) {
throw response.statusText;
}
return response.json();
}
// обращение к серверу для получения всех записей (get)
export async function getAllLines() {
const response = await fetch(`${serverUrl}/items`);
if (!response.ok) {
throw response.statusText;
}
return response.json();
}
// обращение к серверу для получения записи по первичному ключу (id) (get)
// id передается в качестве части пути URL get-запроса
export async function getLine(id) {
const response = await fetch(`${serverUrl}/lines/${id}?_expand=items`);
if (!response.ok) {
throw response.statusText;
}
return response.json();
}
// обращение к серверу для создания записи (post)
// объект отправляется в теле запроса (body)
export async function createLine(name, autor, number, annotation, info, image) {
const itemObject = createLineObject(name, autor, number, annotation, info, image);
const options = {
method: "POST",
body: JSON.stringify(itemObject),
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
},
};
const response = await fetch(`${serverUrl}/items`, options);
if (!response.ok) {
throw response.statusText;
}
return response.json();
}
// обращение к серверу для обновления записи по id (put)
// объект отправляется в теле запроса (body)
// id передается в качестве части пути URL get-запроса
export async function updateLine(id, name, autor, number, annotation, info, image) {
const itemObject = createLineObject(id, name, autor, number, annotation, info, image);
const options = {
method: "PUT",
body: JSON.stringify(itemObject),
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
},
};
const response = await fetch(`${serverUrl}/items/${id}`, options);
if (!response.ok) {
throw response.statusText;
}
return response.json();
}
// обращение к серверу для удаления записи по id (delete)
// id передается в качестве части пути URL get-запроса
export async function deleteLine(id) {
const options = {
method: "DELETE",
};
const response = await fetch(`${serverUrl}/items/${id}`, options);
if (!response.ok) {
throw response.statusText;
}
return response.json();
}

View File

@ -0,0 +1,103 @@
// модуль для работы с элементами управления
// объект для удобного получения элементов
// при обращении к атрибуту объекта вызывается
// нужная функция для поиска элемента
export const cntrls = {
button: document.getElementById("items-add"),
table: document.getElementById("body"),
form: document.getElementById("items-form"),
id: document.getElementById("id"),
name: document.getElementById("name"),
autor: document.getElementById("autor"),
number: document.getElementById("num"),
annotation: document.getElementById("annotation"),
info: document.getElementById("info"),
cover: document.getElementById("image-preview"),
image: document.getElementById("image"),
imagePreview: document.getElementById("image-preview"),
};
// Дефолтное превью
export const imagePlaceholder = "https://via.placeholder.com/200";
// функция создает тег option для select
// <option value="" selected>name</option>
export function createItemsOption(name, value = "", isSelected = false) {
const option = document.createElement("option");
option.value = value || "";
option.selected = isSelected;
option.text = name;
return option;
}
// функция создает ссылку (a) для таблицы
// содержимое тега a заполняется необходимой иконкой (icon)
// при нажатии вызывается callback
// ссылка "оборачивается" тегом td
// <td><a href="#" onclick="callback()"><i class="fa-solid icon"></i></a></td>
function createTableAnchor(icon, callback) {
const i = document.createElement("i");
i.classList.add("fa-solid", icon);
const a = document.createElement("a");
a.href = "#";
a.appendChild(i);
a.onclick = (event) => {
// чтобы в URL не добавлялась решетка
event.preventDefault();
event.stopPropagation();
callback();
};
const td = document.createElement("td");
td.appendChild(a);
return td;
}
// функция создает колонку таблицы с текстом value
// <td>value</td>
function createTableColumn(value) {
const td = document.createElement("td");
td.textContent = value;
return td;
}
// функция создает строку таблицы
// <tr>
// <th scope="row">index + 1</th>
// <td>item.items.name</td>
// <td>parseFloat(item.price).toFixed(2))</td>
// <td>item.count</td>
// <td>parseFloat(item.sum).toFixed(2))</td>
// <td><a href="#" onclick="editCallback()"><i class="fa-solid fa-pencil"></i></a></td>
// <td><a href="#" onclick="editPageCallback()"><i class="fa-solid fa-pen-to-square"></i></a></td>
// <td><a href="#" onclick="deleteCallback()"><i class="fa-solid fa-trash"></i></a></td>
// </tr>
export function createTableRow(item, index, editCallback, deleteCallback) {
const rowNumber = document.createElement("th");
rowNumber.scope = "row";
rowNumber.textContent = index + 1;
const row = document.createElement("tr");
row.id = `line-${item.id}`;
const imgCover = document.createElement("img");
imgCover.src = item.cover;
imgCover.style = "width: 100%"
imgCover.alt = "no cover"
row.appendChild(rowNumber);
row.appendChild(imgCover);
row.appendChild(createTableColumn(item.name + " | " + item.autor));
row.appendChild(createTableColumn(item.number));
// редактировать в модальном окне
row.appendChild(createTableAnchor("fa-pencil", editCallback));
row.appendChild(createTableAnchor("fa-trash", deleteCallback));
return row;
}

View File

@ -0,0 +1,301 @@
// модуль с логикой
import { hideUpdateModal, showUpdateModal } from "./lines-modal";
import {
createLine, deleteLine, getAllItemTypes, getAllLines, getLine, updateLine,
} from "./lines-rest-api";
import {
cntrls, createItemsOption, createTableRow, imagePlaceholder,
} from "./lines-ui";
async function drawItemsSelect() {
// вызов метода REST API для получения списка типов товаров
const data = await getAllItemTypes();
// очистка содержимого select
// удаляется все, что находится между тегами <select></select>
// но не атрибуты
cntrls.itemsType.innerHTML = "";
// пустое значение
cntrls.itemsType.appendChild(createItemsOption("Выберите значение", "", true));
// цикл по результату ответа от сервера
// используется лямбда-выражение
// (item) => {} аналогично function(item) {}
data.forEach((item) => {
cntrls.itemsType.appendChild(createItemsOption(item.name, item.id));
});
}
async function drawLinesTable() {
console.info("Try to load data");
if (!cntrls.table) {
return;
}
// вызов метода REST API для получения всех записей
const data = await getAllLines();
// очистка содержимого table
// удаляется все, что находится между тегами <table></table>
// но не атрибуты
cntrls.table.innerHTML = "";
// цикл по результату ответа от сервера
// используется лямбда-выражение
// (item, index) => {} аналогично function(item, index) {}
data.forEach((item, index) => {
cntrls.table.appendChild(
createTableRow(
item,
index,
// функции передаются в качестве параметра
// это очень удобно, так как аргументы функций доступны только
// в данном месте кода и не передаются в сервисные модули
() => showUpdateModal(item),
() => removeLine(item.id),
),
);
});
}
async function addLine(name, autor, number, annotation, info, image) {
console.info("Try to add item");
// вызов метода REST API для добавления записи
const data = await createLine(name, autor, number, annotation, info, image);
console.info("Added");
console.info(data);
// загрузка и заполнение table
drawLinesTable();
}
async function editLine(id, name, autor, number, annotation, info, image) {
console.info("Try to update item");
// вызов метода REST API для обновления записи
const data = await updateLine(id, name, autor, number, annotation, info, image);
console.info("Updated");
console.info(data);
// загрузка и заполнение table
drawLinesTable();
}
async function removeLine(id) {
if (!confirm("Do you really want to remove this item?")) {
console.info("Canceled");
return;
}
console.info("Try to remove item");
// вызов метода REST API для удаления записи
const data = await deleteLine(id);
console.info(data);
// загрузка и заполнение table
drawLinesTable();
}
// функция для получения содержимого файла в виде base64 строки
// https://ru.wikipedia.org/wiki/Base64
async function readFile(file) {
const reader = new FileReader();
// создание Promise-объекта для использования функции
// с помощью await (асинхронно) без коллбэков (callback)
// https://learn.javascript.ru/promise
return new Promise((resolve, reject) => {
// 2. "Возвращаем" содержимое когда файл прочитан
// через вызов resolve
// Если не использовать Promise, то всю работу по взаимодействию
// с REST API пришлось бы делать в обработчике (callback) функции
// onloadend
reader.onloadend = () => {
const fileContent = reader.result;
// Здесь могла бы быть работа с REST API
// Чтение заканчивает выполняться здесь
resolve(fileContent);
};
// 3. Возвращаем ошибку
reader.onerror = () => {
// Или здесь в случае ошибки
reject(new Error("oops, something went wrong with the file reader."));
};
// Шаг 1. Сначала читаем файл
// Чтение начинает выполняться здесь
reader.readAsDataURL(file);
});
}
// функция для обновления блока с превью выбранного изображения
async function updateImagePreview() {
// получение выбранного файла
// возможен выбор нескольких файлов, поэтому необходимо получить только первый
const file = cntrls.image.files[0];
// чтение содержимого файла в виде base64 строки
const fileContent = await readFile(file);
console.info("base64 ", fileContent);
// обновление атрибута src для тега img с id image-preview
cntrls.imagePreview.src = fileContent;
}
// Функция для обработки создания и редактирования элементов таблицы через модальное окно
// Если хотите делать через страницу, то удалите эту функцию
export function linesForm() {
console.info("linesForm");
// загрузка и заполнение select со списком товаров
//drawItemsSelect();
// загрузка и заполнение table
drawLinesTable();
// Вызов функции обновления превью изображения при возникновении
// события oncahnge в тэге input с id image
cntrls.image.addEventListener("change", () => updateImagePreview());
// обработчик события нажатия на кнопку для показа модального окна
cntrls.button.addEventListener("click", () => showUpdateModal(null));
// обработчик события отправки формы
// возникает при нажатии на кнопку (button) с типом submit
// кнопка должна находится внутри тега form
cntrls.form.addEventListener("submit", async (event) => {
console.info("Form onSubmit");
// отключение стандартного поведения формы при отправке
// при отправке страница обновляется и JS перестает работать
event.preventDefault();
event.stopPropagation();
// если форма не прошла валидацию, то ничего делать не нужно
if (!cntrls.form.checkValidity()) {
return;
}
let imageBase64 = "";
// Получение выбранного пользователем изображения в виде base64 строки
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
// дефолтное изображение
if (cntrls.imagePreview.src !== imagePlaceholder) {
// Загрузка содержимого атрибута src тэга img с id image-preview
// Здесь выполняется HTTP запрос с типом GET
const result = await fetch(cntrls.imagePreview.src);
// Получение из HTTP-ответа бинарного содержимого
const blob = await result.blob();
// Получение base64 строки для файла
// Здесь выполняется Promise из функции readFile
// Promise позволяет писать линейный код для работы с асинхронными методами
// без использования обработчиков (callback) с помощью await
imageBase64 = await readFile(blob);
}
// получение id строки для редактирования
// это значение содержится в скрытом input
const currentId = cntrls.id.value;
// если значение id не задано,
// то необходимо выполнить добавление записи
// иначе обновление записи
if (!currentId) {
await addLine(
cntrls.name.value, cntrls.autor.value, cntrls.number.value, cntrls.annotation.value, cntrls.info.value,
imageBase64,
);
} else {
await editLine(
currentId,
cntrls.name.value, cntrls.autor.value, cntrls.number.value, cntrls.annotation.value, cntrls.info.value,
imageBase64,
);
}
// после выполнения добавления/обновления модальное окно скрывается
hideUpdateModal();
});
}
// Функция для обработки создания и редактирования элементов таблицы через страницу page-edit.html
// Если хотите делать через модальное окно, то удалите эту функцию
export async function linesPageForm() {
console.info("linesPageForm");
// загрузка и заполнение select со списком товаров
//drawItemsSelect();
// func1 = (id) => {} аналогично function func1(id) {}
const goBack = () => location.assign("/page4.html");
// Вызов функции обновления превью изображения при возникновении
// события onchange в тэге input с id image
cntrls.image.addEventListener("change", () => updateImagePreview());
// получение параметров GET-запроса из URL
// параметры перечислены после символа ? (?id=1&color=black&...)
const urlParams = new URLSearchParams(location.search);
// получение значения конкретного параметра (id)
// указан только при редактировании
const currentId = urlParams.get("id");
// если id задан
if (currentId) {
try {
// вызов метода REST API для получения записи по первичному ключу(id)
const line = await getLine(currentId);
// заполнение формы для редактирования
cntrls.itemsType.value = line.itemsId;
cntrls.price.value = line.price;
cntrls.count.value = line.count;
// заполнение превью
// Если пользователь выбрал изображение, то оно загружается
// в тэг image с id image - preview
// иначе устанавливается заглушка, адрес которой указан в imagePlaceholder
cntrls.imagePreview.src = line.image ? line.image : imagePlaceholder;
} catch {
// в случае ошибки происходит возврат к page4
goBack();
}
}
// обработчик события отправки формы
// возникает при нажатии на кнопку (button) с типом submit
// кнопка должна находится внутри тега form
cntrls.form.addEventListener("submit", async (event) => {
console.info("Form onSubmit");
// отключение стандартного поведения формы при отправке
// при отправке страница обновляется и JS перестает работать
event.preventDefault();
event.stopPropagation();
// если форма не прошла валидацию, то ничего делать не нужно
if (!cntrls.form.checkValidity()) {
return;
}
let imageBase64 = "";
// Получение выбранного пользователем изображения в виде base64 строки
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
// дефолтное изображение
if (cntrls.imagePreview.src !== imagePlaceholder) {
// Загрузка содержимого атрибута src тэга img с id image-preview
// Здесь выполняется HTTP запрос с типом GET
const result = await fetch(cntrls.imagePreview.src);
// Получение из HTTP-ответа бинарного содержимого
const blob = await result.blob();
// Получение base64 строки для файла
// Здесь выполняется Promise из функции readFile
// Promise позволяет писать линейный код для работы с асинхронными методами
// без использования обработчиков (callback) с помощью await
imageBase64 = await readFile(blob);
}
// если значение параметра запроса не задано,
// то необходимо выполнить добавление записи
// иначе обновление записи
if (!currentId) {
await addLine(
cntrls.itemsType.value,
cntrls.price.value,
cntrls.count.value,
imageBase64,
);
} else {
await editLine(
currentId,
cntrls.itemsType.value,
cntrls.price.value,
cntrls.count.value,
imageBase64,
);
}
// возврат к странице page4
goBack();
});
}

View File

View File

@ -0,0 +1,14 @@
let idOfBook = 0
export function rememberIdOfBook(id){
idOfBook = id
}
export function createPageOfBook(){
console.log(idOfBook)
}
export default createPageOfBook

View File

@ -0,0 +1,31 @@
// модуль используется для валидации форма на странице
function validation() {
// поиск всех форма с классом .needs-validation
const forms = document.querySelectorAll("form.needs-validation");
for (let i = 0; i < forms.length; i += 1) {
const form = forms[i];
form.addEventListener("submit", (event) => {
// если форма не прошла валидацию
// то выключить стандартное действие
if (!form.checkValidity()) {
event.preventDefault();
// предотвращает распространение preventDefault
// на другие объекты
event.stopPropagation();
}
// добавляет к форме класс was-validated
form.classList.add("was-validated");
});
}
}
export default validation;

5127
3_Lab/testBootstrap_main/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
{
"name": "vite-project",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"start": "vite",
"serve": "http-server -p 3000 ./dist/",
"build": "vite build",
"rest": "json-server --watch data.json -p 8081",
"dev": "npm-run-all --parallel rest start",
"prod": "npm-run-all build --parallel serve rest"
},
"dependencies": {
"bootstrap": "5.3.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"eslint": "^8.45.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"http-server": "14.1.1",
"json-server": "0.17.4",
"npm-run-all": "4.1.5",
"typescript": "^5.0.2",
"vite": "^4.4.5"
}
}

View File

@ -0,0 +1,90 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>О нас</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<script src="/js/bootstrap.js"></script>
<link rel="stylesheet" href="/fontello.css" type="text/css" />
<link rel="stylesheet" href="style.css">
</head>
<body class="d-flex flex-column min-vh-100">
<header>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/index.html">
<img src="/src/logoOfLibrary.png" alt="" width="80" class="d-inline-block align-text-top" border-radius="20%">
</a>
<a class="about-us-link nav-link link-light fs-5" href="/pageAboutUs.html">О нас</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="navbar-collapse collapse justify-content-end p-3 bg-dark" id="navbarNav">
<div class="navbar-nav p-3">
<a class="nav-link fs-5 text-light " href="./pageCatalog.html">Каталог</a>
<a class="nav-link fs-5 text-light " href="./pageBasket.html">Корзина</a>
</div>
<section class="menu align-self-center">
<a class="nav-link text-end fs-5 lh-2 text-light" href="./pageSignUp.html">Зарегистрироваться</a>
<a class="nav-link text-end fs-6 text-light" href="./pageSignIn.html">Уже есть аккаунт?</a>
</section>
</div>
</div>
</nav>
</header>
<main class="container-fluid p-2">
<div class="row justify-content-center">
<div class="col-of-about col-md-9 mb-4 rounded">
<div class=" row pt-4 pb-4">
<div class="col-auto m-1 align-self-center"> <img src="/src/logoOfLibrary.png" alt="" width="80" class="d-inline-block align-text-top" border-radius="20%"></div>
<div class="col-md-9 col-7 align-self-center"> <h1 class="text-about-us-article text-white fs-2 text-start ">BookCamp: Библиотека твоего города</h1></div>
</div>
</div>
<div class="col-md-9 p-4">
<p class="text-about-us mb-4">
Добро пожаловать на сайт городской библиотеки! Рады приветствовать вас здесь, в виртуальном пространстве, где вы сможете погрузиться в мир книг и знаний. Наша библиотека - это место, где каждый может найти что-то интересное и полезное для себя. Мы предлагаем широкий выбор литературы, электронных ресурсов, а также различные мероприятия и программы для всех возрастов. Будьте с нами и откройте для себя новые горизонты чтения и образования!В нашей библиотеке вы найдете все, что нужно для удовлетворения своей любознательности и жажды знаний. У нас есть огромный выбор книг по самым разным темам: от классической литературы до современных бестселлеров, от научно-популярных изданий до произведений искусства. Мы также предлагаем электронные ресурсы, которые позволяют вам читать книги онлайн или скачивать их на свои устройства. Таким образом, вы можете наслаждаться чтением в любое удобное для вас время и место.
</p>
<p class="text-about-us mb-4">Наша библиотека не только предлагает чтение, но и является центром культурной жизни города. Мы организуем различные мероприятия, такие как лекции, дискуссии, книжные клубы и выставки. У нас также есть специальные программы для детей и подростков, которые помогают им развивать свои навыки чтения и письма, а также познавать мир вокруг себя. Мы приглашаем всех желающих присоединиться к нашим мероприятиям и обменяться своими идеями и впечатлениями.Кроме того, мы предлагаем услуги по поддержке исследований и обучению. Наша библиотека является надежным источником информации, где вы можете найти актуальные и достоверные материалы для своих проектов и заданий. Мы также предлагаем помощь в использовании электронных ресурсов и поиске нужной информации.</p>
<p class="text-about-us mb-4">Мы стремимся создать комфортную и дружественную атмосферу для всех посетителей нашей библиотеки. Наш персонал всегда готов помочь вам найти нужную книгу или ответить на ваши вопросы. Мы также предлагаем возможность зарегистрироваться в библиотеке онлайн, чтобы получить доступ к нашим электронным ресурсам и оставлять отзывы о прочитанных книгах.Мы верим, что чтение и образование - это ключи к развитию и саморазвитию. Поэтому мы приглашаем вас присоединиться к нашей библиотечной семье и открыть для себя новые горизонты. Здесь вы найдете не только знания, но и вдохновение, удовольствие и возможность расширить свой кругозор. Погрузитесь в мир книг и знаний вместе с нами и дайте своему уму возможность расти и расцветать. Добро пожаловать в городскую библиотеку!</p>
</div>
</div>
</main>
<footer class="footer mt-auto d-flex flex-shrink-0 align-items-center">
<h3 class="ps-0 me-3">Наши соцсети</h3>
<div class="group-sites" role="group">
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-facebook.png" class="button-sm m-auto " alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-viber.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-tg.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-whats-up.png" class="button-sm m-auto" alt="" width="35" ></a>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,302 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Страница администратора</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="/js/bootstrap.js"></script>
<script src="/js/lines-rest-api.js"></script>
<link href="./node_modules/@fortawesome/fontawesome-free/css/all.min.css" rel="stylesheet" />
<link rel="stylesheet" href="/fontello.css" type="text/css" />
<link rel="stylesheet" href="style.css">
</head>
<body class="d-flex flex-column min-vh-100">
<header>
<nav class="navbar navbar-expand-md navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/index.html">
<img src="/src/logoOfLibrary.png" alt="" width="80" class="d-inline-block align-text-top" border-radius="20%">
</a>
<a class="about-us-link nav-link link-light fs-5" href="/pageAboutUs.html">О нас</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="navbar-collapse collapse justify-content-end p-3" id="navbarNav">
<div class="navbar-nav p-3">
<a class="nav-link fs-5 text-light " href="./pageCatalog.html">Каталог</a>
<a class="nav-link fs-5 text-light " href="./pageBasket.html">Корзина</a>
</div>
<section class="menu align-self-center">
<a class="nav-link text-end fs-5 lh-2 text-light" href="./pageSignUp.html">Зарегистрироваться</a>
<a class="nav-link text-end fs-6 text-light" href="./pageSignIn.html">Уже есть аккаунт?</a>
</section>
</div>
</div>
</nav>
</header>
<main class="container-fluid p-2">
<div class="row">
<!-- <div class="col-sm-4">
<div id="items-update" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false">
<div >
<form id="items-form" class="needs-validation" novalidate>
<h2>Добавить книгу в базу</h2>
<label class="mt-3">Фото обложки</label>
<input type="file" name="image" class="form-control mb-4" accept="image/*"
onchange="updatePreview(this, 'image-preview')">
<div class="d-none">
<h2 class="border-bottom pb-3 mb-4 ">Avatar Preview</h2>
<div class="text-center">
<img id="image-preview" src="./src/covers/default.png" style="width:400px"
class="rounded rounded-circle" alt="placeholder">
</div>
</div>
<label>Название книги</label>
<div class="input-group mb-5 border-bottom">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="name-book" type="text" class="form-control border-0 placeholder-class" aria-label="Email" aria-describedby="basic-addon1" required>
</div>
<label>Автор</label>
<div class="input-group mb-3 border-bottom mb-5">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="autor" type="text" class="form-control border-0 placeholder-class" aria-label="Email" aria-describedby="basic-addon1" >
</div>
<label>ID</label>
<div class="input-group border-bottom">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="id" type="text" class="form-control border-0 placeholder-class" aria-label="ID" aria-describedby="basic-addon1">
</div>
<div id="emailHelp" class="form-text mb-3">Для редактирования данных введите существующий ID</div>
<label>Количество книг</label>
<div class="input-group mb-3 border-bottom mb-5">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="number" type="text" class="form-control border-0 placeholder-class" aria-label="Email" aria-describedby="basic-addon1">
</div>
<label>Аннотация к книге</label>
<div class="input-group mb-3 border-bottom mb-5">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="annotation" type="text" class="form-control border-0 placeholder-class" aria-label="Email" aria-describedby="basic-addon1">
</div>
<label>Храктеристики книги</label>
<div class="input-group mb-3 border-bottom mb-5" max-width="100px">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="info" type="text" class="form-control border-0 placeholder-class" aria-label="Email" aria-describedby="basic-addon1">
</div>
<button class="btn-rectangle" type="submit" id="items-add" onclick="upload()">Добавить книгу</button>
</form> -->
</div>
<button class="btn-rectangle mb-3" id="items-add">Добавить книгу</button>
</div>
</div>
<div class="row">
<div class="col-8">
<h2>В наличии</h2>
<table class="table table-borderless table-hover align-middle" id="items-table">
<thead>
<tr>
<th scope="col">ID</th >
<th scope="col" style="width:7px">Обложка</th >
<th scope="col">Название и автор</th>
<th scope="col">Количество</th>
<th scope="col" style="width:7px"></th>
<th scope="col" style="width:7px"></th>
</tr>
</thead>
<tbody id="body">
<!-- <tr>
<td><p class="mb-0 font-basket">Ведьмак. Меч предназначения</p>
<p class="mb-0 font-basket">Анджей Сапковский</p>
<div class="input-group quantity-goods mt-1">
<input type="button" value="-" id="button_minus" class="minus">
<input class="input-number" type="number" step="1" min="1" max="10" id="num_count" name="quantity" value="1" title="Qty">
<input type="button" value="+" id="button_plus" class="plus">
</div>
</td>
<td class="align-bottom">
<div class="btn btn-delete"> <img src="/src/icons/icons_sigh/trash.svg" alt=""></div>
</td>
</tr>
<tr>
<th scope="row"><img src="/src/covers/image2book.png" alt="" width="80px"></th></th>
<td><p class="mb-0 font-basket">Ведьмак. Последнее желание</p>
<p class="mb-0 font-basket">Анджей Сапковский</p>
<div class="input-group quantity_goods mt-1 ">
<input type="button" value="-" id="button_minus" class="minus">
<input class="input-number" type="number" step="1" min="1" max="10" id="num_count" name="quantity" value="1" title="Qty">
<input type="button" value="+" id="button_plus" class="plus">
</div>
</td>
<td class="align-bottom">
<div class="btn btn-delete"> <img src="/src/icons/icons_sigh/trash.svg" alt=""></div>
</td>
</tr> -->
</tbody>
</table>
<hr>
<div class="row">
</div>
</div>
</div></div>
</main>
<footer class="footer mt-auto d-flex flex-shrink-0 align-items-center">
<h3 class="ps-0">Наши соцсети</h3>
<div class="group-sites" role="group">
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-facebook.png" class="button-sm m-auto " alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-viber.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-tg.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-whats-up.png" class="button-sm m-auto" alt="" width="35" ></a>
</div>
</footer>
<div id="items-update" class="modal fade" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-scrollable">
<form id="items-form" class="needs-validation" novalidate>
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="items-update-title">Данные</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-2">
<label class="form-label" for="image">Изображение</label>
<input id="image" type="file" name="image" class="form-control" accept="image/*">
</div>
<div class="text-center">
<img id="image-preview" src="https://via.placeholder.com/200" class="rounded rounded-circle"
alt="placeholder">
</div>
<label class="mt-3">Название книги</label>
<input id="name" class="form-control" type="text" required>
<label class="mt-3">Автор</label>
<input id="autor" class="form-control" type="text" required>
<label class="mt-3">ID</label>
<input id="id" class="form-control" type="text">
<label class="mt-3">Количество</label>
<input id="num" class="form-control" type="number" required>
<label class="mt-3">Аннотация к книге</label>
<input id="annotation" name="price" class="form-control" type="text" required>
<label class="mt-3">Храктеристики книги</label>
<input id="info" name="price" class="form-control" type="text" required>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
<button type="submitModal" class="btn btn-primary">Сохранить</button>
</div>
</div>
</form>
</div>
<script type="module">
import {getLine} from "./js/lines-rest-api";
function notUndefind(item){
if (item === undefined || item === ""){
return "-"
} return item
}
async function getRow(id, modal){
const row = await getLine(id);
const img = document.createElement("img");
img.src = row.cover
img.alt = "no cover"
img.style.width = "100%"
// img.style.width = "90px"
console.log(img)
document.getElementById("coverModal").innerHTML = ""
document.getElementById("coverModal").appendChild(img)
console.log(document.getElementById("coverModal"))
document.getElementById("nameModal").innerHTML = notUndefind(row.name)
document.getElementById("autorModal").innerHTML = notUndefind(row.autor)
document.getElementById("idModal").innerHTML = notUndefind(row.id)
document.getElementById("annotationModal").innerHTML = notUndefind(row.annotation)
document.getElementById("infoModal").innerHTML = notUndefind(row.info)
return row
}
$('#items-table').on('click', 'tr', function(){
const id = event.target.parentNode.id
getRow(id,document.getElementById("items-show"))
$("#items-show").modal('show');
});
</script>
<script type="module">
import validation from "./js/validation";
import { linesForm } from "./js/lines";
document.addEventListener('DOMContentLoaded', () => {
validation();
linesForm();
});
</script>
</body>
</html>

View File

@ -0,0 +1,144 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Корзина</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<script type="module" src="./js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/fontello.css" type="text/css" />
<link rel="stylesheet" href="style.css">
<script src="app.js" defer></script>
</head>
<body class="d-flex flex-column min-vh-100">
<header>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/index.html">
<img src="/src/logoOfLibrary.png" alt="" width="80" class="d-inline-block align-text-top" border-radius="20%">
</a>
<a class="about-us-link nav-link link-light fs-5" href="/pageAboutUs.html">О нас</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="navbar-collapse collapse justify-content-end p-3 bg-dark" id="navbarNav">
<div class="navbar-nav p-3">
<a class="nav-link fs-5 text-light " href="./pageCatalog.html">Каталог</a>
<a class="nav-link fs-5 text-light " href="./pageBasket.html">Корзина</a>
</div>
<section class="menu align-self-center">
<a class="nav-link text-end fs-5 lh-2 text-light" href="./pageSignUp.html">Зарегистрироваться</a>
<a class="nav-link text-end fs-6 text-light" href="./pageSignIn.html">Уже есть аккаунт?</a>
</section>
</div>
</div>
</nav>
</header>
<main class="container-fluid p-2">
<h1>Подборка</h1>
<div class="row">
<div class="col-8">
<table class="table table-borderless" id="table">
<thead>
<tr>
<th scope="col">Товар</th>
<th scope="col">Описание</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row row-of-pictures" allign="center"><img src="/src/covers/image1book.png" alt="" width="80px"></th>
<td><p class="mb-0 font-basket">Ведьмак. Меч предназначения</p>
<p class="mb-0 font-basket">Анджей Сапковский</p>
<div class="input-group quantity-goods mt-1">
<input type="button" value="-" id="button_minus" class = "minus">
<input class="input-number" type="number" step="1" min="1" max="10" value="1" title="Qty">
<input type="button" value="+" id="button_plus" class="plus">
</div>
</td>
<td class="align-bottom">
<div class="btn btn-delete"> <img src="/src/icons/icons_sigh/trash.svg" alt=""></div>
</td>
</tr>
<tr>
<th scope="row"><img src="/src/covers/image2book.png" alt="" width="80px"></th></th>
<td><p class="mb-0 font-basket">Ведьмак. Последнее желание</p>
<p class="mb-0 font-basket">Анджей Сапковский</p>
<div class="input-group quantity-goods mt-1 ">
<input type="button" value="-" id="button_minus" class = "minus">
<input class="input-number" type="number" step="1" min="1" max="10" value="1" title="Qty">
<input type="button" value="+" id="button_plus" class="plus">
</div>
</td>
<td class="align-bottom">
<div class="btn btn-delete"> <img src="/src/icons/icons_sigh/trash.svg" alt=""></div>
</td>
</tr>
</tbody>
</table>
<hr>
<!-- <a href="./pageCatalog.html">< К библиотеке </a> -->
</div>
</div>
</main>
<footer class="footer mt-auto d-flex flex-shrink-0 align-items-center">
<h3 class="ps-0 me-2">Наши соцсети</h3>
<div class="group-sites" role="group">
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-facebook.png" class="button-sm m-auto " alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-viber.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-tg.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-whats-up.png" class="button-sm m-auto" alt="" width="35" ></a>
</div>
</footer>
<script>
let listOfCounters = document.getElementsByClassName('quantity-goods')
document.getElementById('table')
.addEventListener('click', event => { // Step 2
if (event.target.className === 'minus') {
event.target.parentNode.getElementsByClassName("input-number")[0].value > 1 ? event.target.parentNode.getElementsByClassName("input-number")[0].value -= 1 : 1
}
if (event.target.className === 'plus') { // Step 3
event.target.parentNode.getElementsByClassName("input-number")[0].value++
}
});
</script>
</body>
</html>

View File

@ -0,0 +1,128 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Каталог</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<script src="/js/bootstrap.js"></script>
<script src="/js/catalog.js"></script>
<link rel="stylesheet" href="/fontello.css" type="text/css" />
<link rel="stylesheet" href="style.css">
</head>
<body class="d-flex flex-column min-vh-100">
<header>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/index.html">
<img src="/src/logoOfLibrary.png" alt="" width="80" class="d-inline-block align-text-top" border-radius="20%">
</a>
<a class="about-us-link nav-link link-light fs-5" href="/pageAboutUs.html">О нас</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="navbar-collapse collapse justify-content-end p-3 bg-dark" id="navbarNav">
<div class="navbar-nav p-3">
<a class="nav-link fs-5 text-light " href="./pageCatalog.html">Каталог</a>
<a class="nav-link fs-5 text-light " href="./pageBasket.html">Корзина</a>
</div>
<section class="menu align-self-center">
<a class="nav-link text-end fs-5 lh-2 text-light" href="./pageSignUp.html">Зарегистрироваться</a>
<a class="nav-link text-end fs-6 text-light" href="./pageSignIn.html">Уже есть аккаунт?</a>
</section>
</div>
</div>
</nav>
</header>
<main class="container-fluid p-2">
<h3 class="ms-5 mt-4 mb-4">Каталог</h3>
<div id="catalog">
<div class="row justify-content-evenly ">
<div class="col-md-3 col-6 mb-sm-0 align-self-end ">
<div class="card" style="width: 100%;">
<a href="/pageOfBook1.html"> <img src="/src/covers/image1book.png" class="card-img-top" alt="..." ></a>
<div class="card-body">
<p class="card-title mt-0 mb-0">Ведьмак. Последнее желание</p>
<p class="card-text ">Анджей Сапковский</p>
<a href="/pageOfBook1.html" class="btn btn-catalog btn-primary rounded-0 mt-1 border">Добавить в корзину</a>
</div>
</div>
</div>
<div class="col-md-3 col-6 align-self-end offset-md-0">
<div class="card" style="width: 100%;">
<a href="/pageOfBook1.html"> <img src="/src/covers/image2book.png" class="card-img-top" alt="..." ></a>
<div class="card-body">
<p class="card-title mt-0 mb-0">Ведьмак. Меч предназначения</p>
<p class="card-text">Анджей Сапковский</p>
<a href="#" class="btn-catalog btn btn-primary rounded-0 mt-1 border">Добавить в корзину</a>
</div>
</div>
</div>
<div class="col-md-3 col-6 align-self-end col-bott">
<div class="card" style="width: 100%;">
<a href="/pageOfBook1.html"> <img src="/src/covers/image3book.png" class="card-img-top" alt="..." ></a>
<div class="card-body">
<p class="card-title mt-0 mb-0">Ведьмак. Кровь эльфов</p>
<p class="card-text">Анджей Сапковский</p>
<a href="#" class="btn-catalog btn btn-primary rounded-0 mt-1 border ">Добавить в корзину</a>
</div>
</div>
</div>
<div class="row justify-content-evenly mt-4">
<div class="col-md-3 col-6 align-self-end col-bott">
<div class="card" style="width: 100%;">
<a href="/pageAdmin.html"> <img src="/src/covers/addbook1.png" class="card-img-top" alt="..." ></a>
<div class="card-body">
<p class="card-title mt-0 mb-0">???</p>
<p class="card-text">?????</p>
<a href="#" class="btn btn-catalog btn-primary rounded-0 mt-1 border ">Добавить книгу</a>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<footer class="footer mt-auto d-flex flex-shrink-0 align-items-center">
<h3 class="ps-0 me-2">Наши соцсети</h3>
<div class="group-sites" role="group">
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-facebook.png" class="button-sm m-auto " alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-viber.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-tg.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-whats-up.png" class="button-sm m-auto" alt="" width="35" ></a>
</div>
</footer>
<script type="module">
import drawCardsCatalog from "./js/catalog";
document.addEventListener('DOMContentLoaded', () => {
drawCardsCatalog();
});
</script>
</body>
</html>

View File

@ -0,0 +1,122 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Страница администратора</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="/js/bootstrap.js"></script>
<script src="/js/lines-rest-api.js"></script>
<link rel="stylesheet" href="/fontello.css" type="text/css" />
<link rel="stylesheet" href="style.css">
</head>
<body class="d-flex flex-column min-vh-100">
<header>
<nav class="navbar navbar-expand-md navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/index.html">
<img src="/src/logoOfLibrary.png" alt="" width="80" class="d-inline-block align-text-top" border-radius="20%">
</a>
<a class="about-us-link nav-link link-light fs-5" href="/pageAboutUs.html">О нас</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="navbar-collapse collapse justify-content-end p-3" id="navbarNav">
<div class="navbar-nav p-3">
<a class="nav-link fs-5 text-light " href="./pageCatalog.html">Каталог</a>
<a class="nav-link fs-5 text-light " href="./pageBasket.html">Корзина</a>
</div>
<section class="menu align-self-center">
<a class="nav-link text-end fs-5 lh-2 text-light" href="./pageSignUp.html">Зарегистрироваться</a>
<a class="nav-link text-end fs-6 text-light" href="./pageSignIn.html">Уже есть аккаунт?</a>
</section>
</div>
</div>
</nav>
</header>
<main class="container-fluid p-2">
<div class="row">
<div class="col-sm-6">
<div id="items-update" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false">
<div >
<form id="items-form" class="needs-validation" novalidate>
<h2>Добавить книгу в базу</h2>
<label class="mt-3">Фото обложки</label>
<input type="file" name="image" class="form-control mb-4" accept="image/*"
onchange="updatePreview(this, 'image-preview')">
<div class="d-none">
<h2 class="border-bottom pb-3 mb-4 ">Avatar Preview</h2>
<div class="text-center">
<img id="image-preview" src="./src/covers/default.png" style="width:400px"
class="rounded rounded-circle" alt="placeholder">
</div>
</div>
<label>Название книги</label>
<div class="input-group mb-5 border-bottom">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="name-book" type="text" class="form-control border-0 placeholder-class" aria-label="Email" aria-describedby="basic-addon1" required>
</div>
<label>Автор</label>
<div class="input-group mb-3 border-bottom mb-5">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="autor" type="text" class="form-control border-0 placeholder-class" aria-label="Email" aria-describedby="basic-addon1" >
</div>
<label>ID</label>
<div class="input-group border-bottom">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="id" type="text" class="form-control border-0 placeholder-class" aria-label="ID" aria-describedby="basic-addon1">
</div>
<div id="emailHelp" class="form-text mb-3">Для редактирования данных введите существующий ID</div>
<label>Количество книг</label>
<div class="input-group mb-3 border-bottom mb-5">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="number" type="text" class="form-control border-0 placeholder-class" aria-label="Email" aria-describedby="basic-addon1">
</div>
<label>Аннотация к книге</label>
<div class="input-group mb-3 border-bottom mb-5">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="annotation" type="text" class="form-control border-0 placeholder-class" aria-label="Email" aria-describedby="basic-addon1">
</div>
<label>Храктеристики книги</label>
<div class="input-group mb-3 border-bottom mb-5" max-width="100px">
<span class="input-group-text border-0 bg-white" id="basic-addon1"></span>
<input id="info" type="text" class="form-control border-0 placeholder-class" aria-label="Email" aria-describedby="basic-addon1">
</div>
<button class="btn-rectangle" type="submit" id="items-add" onclick="upload()">Добавить книгу</button>
<a href="pageAdmin.html" class="btn-rectangle-white">Перейти на страницу администратора</a>
</form>
</div>
</main>
<script type="module">
import validation from "./js/validation";
import { linesForm } from "./js/lines";
document.addEventListener('DOMContentLoaded', () => {
validation();
linesForm();
});
</script>
</body>
</html>

View File

@ -0,0 +1,130 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>"Последнее желание"</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<script src="/js/bootstrap.js"></script>
<link rel="stylesheet" href="/fontello.css" type="text/css" />
<link rel="stylesheet" href="style.css">
</head>
<body class="d-flex flex-column min-vh-100">
<header>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<img src="/src/logoOfLibrary.png" alt="" width="80" class="d-inline-block align-text-top" border-radius="20%">
</a>
<a class="about-us-link nav-link link-light fs-5" href="/pageAboutUs.html">О нас</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="navbar-collapse collapse justify-content-end p-3 bg-dark" id="navbarNav">
<div class="navbar-nav p-3">
<a class="nav-link fs-5 text-light " href="./pageCatalog.html">Каталог</a>
<a class="nav-link fs-5 text-light " href="./pageBasket.html">Корзина</a>
</div>
<section class="menu align-self-center">
<a class="nav-link text-end fs-5 lh-2 text-light" href="./pageSignUp.html">Зарегистрироваться</a>
<a class="nav-link text-end fs-6 text-light" href="./pageSignIn.html">Уже есть аккаунт?</a>
</section>
</div>
</div>
</nav>
</header>
<main class="container-fluid p-2">
<div class="mb-3" style="max-width: auto;">
<div class="row g-0 justify-content-center">
<div class="col-lg-3 col-sm-6 col-4 align-self-center">
<img src="/src/covers/image1book.png" class="img-fluid d-flex " alt="...">
</div>
<div class="col-lg-4 col-sm-6 ps-3 align-self-center">
<div class="card-body">
<h5><span class="badge ">Выбор библиотеки!</span></h5>
<h5 class="card-title">Ведьмак. Последнее желание</h5>
<p class="card-text">Анджей Сапковский</p>
<small class="text-body-secondary ">
<div class="row d-flex">
<div class="col-sm-12 col-6">
<p class="card-text mb-1">ID товара2577371</p>
<p class="card-text mb-2">Цикл: Ведьмак</p>
<p class="card-text mb-2">Издательство: АСТ</p>
<p class="card-text mb-2">Серия: Сапковский с иллюстрациями</p>
<p class="card-text mb-2">Год издания: 2022</p>
<p class="card-text mb-2">ISBN978-5-17-102028-6</p>
</div>
<div class="col-sm-12 col-6">
<p class="card-text mb-2">Количество страниц: 320</p>
<p class="card-text mb-2">Размер: 24.2x16.7999x2</p>
<p class="card-text mb-2">Тип обложки: Твердый переплёт</p>
<p class="card-text mb-2">Тираж: 8000</p>
<p class="card-text mb-2">Вес, г: 629</p>
</div>
</div>
</small>
<div class="d-flex justify-content-center justify-content-sm-start">
<a href="#" class="btn btn-rectangle rounded-0 text-light ">Добавить в корзину</a>
</div>
</div>
</div>
<div class="card-description col-lg-5 rounded mt-2" >
<p class="text-light p-3 fs-4">
Аннотация к книге Ведьмак: Последнее желание
</p>
<p class="card-description-text text-light p-3">
Он уничтожает чудовищ и выручает попавших в беду… как правило, за деньги. Он виртуозно владеет мечом… и никогда не помышлял о военной карьере. Он защищает людей… которые его презирают, ненавидят и боятся. Он странствующий рыцарь… без шпор, девиза, замка и прекрасной дамы. А впрочем, прекрасная дама обязательно будет. А еще будут чары и тайны, неразделенная любовь и нелегкий выбор, схватки не на жизнь, а на смерть, странствия, песни и, конечно, сказки — знакомые всем с детства и разительно отличные от того, к чему мы привыкли.Сага А. Сапковского давно занимает почетное место в мировой традиции жанра фэнтези, а Геральт стал культовым персонажем не только в мире литературы, но и в универсуме компьютерных игр. Первая книга из цикла «Ведьмак» впервые выходит с иллюстрациями Дениса Гордеева, созданными специально для этого издания.
</p>
</div>
</div>
</div>
</div>
</main>
<footer class="footer mt-auto d-flex flex-shrink-0 align-items-center">
<h3 class="ps-0 me-2">Наши соцсети</h3>
<div class="group-sites" role="group">
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-facebook.png" class="button-sm m-auto " alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-viber.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-tg.png" class="button-sm m-auto" alt="" width="35" ></a>
<a href="https://vk.com/valannn" ><img src="src/social_media/logo-whats-up.png" class="button-sm m-auto" alt="" width="35" ></a>
</div>
</footer>
<script type="module">
import createPageOfBook from "./js/page";
document.addEventListener('DOMContentLoaded', () => {
createPageOfBook();
});
</script>
</body>
</html>

View File

@ -0,0 +1,87 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Вход</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<script src="/js/bootstrap.js"></script>
<link rel="stylesheet" href="/fontello.css" type="text/css" />
<link rel="stylesheet" href="style.css">
</head>
<body class="d-flex flex-column min-vh-100">
<main class="container-fluid p-2">
<div class="row g-0 justify-content-end">
<div class="col-xl-4 col-10 align-self-center justify-content-center">
<div class="row g-0">
<div class="col-md-3">
<a class="nav-link m-0 justify-content-start" href="/index.html"><img src="/src/logoOfLibrary.png" alt="" width="80" class="d-inline-block align-text-top" border-radius="20%"></a>
</div>
<div class="row g-0 row-of-inter">
<div class="col-10">
<div class="conteiner">
<h2 class="mb-4">Вход</h2>
<h3>Если у вас нет аккаунта,</h3>
<h3 class="mb-5">вы можете <a href="/pageSignUp.html">Зарегистрироваться!</a></h3>
</div>
<form class="needs-validation">
<label>Email</label>
<div class="input-group mb-5 border-bottom">
<span class="input-group-text border-0 bg-white" id="basic-addon1"> <img src="/src/icons/icons_sigh/envelope.svg" alt=""></span>
<input type="text" class="form-control border-0" placeholder="Введите вашу почту" aria-label="Email" required>
<div class="valid-feedback">Email заполнен</div>
<div class="invalid-feedback">Email не заполнен</div>
</div>
<label>Password</label>
<div class="input-group mb-5 border-bottom">
<span class="input-group-text border-0 bg-white" id="basic-addon1"> <img src="/src/icons/icons_sigh/lock.svg" alt=""></span>
<input type="text" class="form-control border-0" placeholder="Введите ваш пароль" aria-label="Password" aria-describedby="basic-addon1" required>
</div>
<button class="btn-sign btn btn-lg mt-5 shadow border text-light" type="submit">Вход</button>
</form>
</div>
</div>
</div>
</div>
<div class="col-auto d-none d-xl-block">
<img class="picture-sigh" src="/src/banners/cover.png" alt="" width="70%">
</div>
</div>
</main>
<script type="module">
import validation from "./js/validation";
document.addEventListener('DOMContentLoaded', () => {
validation();
});
</script>
</body>
</html>

View File

@ -0,0 +1,89 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Регистрация</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<script src="/js/bootstrap.js"></script>
<link rel="stylesheet" href="/fontello.css" type="text/css" />
<link rel="stylesheet" href="style.css">
</head>
<body class="d-flex flex-column min-vh-100">
<main class="container-fluid p-2">
<div class="row g-0 justify-content-end">
<div class="col-xl-4 col-10 align-self-center justify-content-center">
<div class="row g-0">
<div class="col-md-3">
<a class="nav-link m-0 justify-content-start" href="/index.html"><img src="/src/logoOfLibrary.png" alt="" width="80" class="d-inline-block align-text-top" border-radius="20%"></a>
</div>
<div class="row g-0 row-of-inter">
<div class="col-10">
<div class="conteiner mb-4">
<h2>Регистрация</h2>
<h3>Если у вас уже есть аккаунт,</h3>
<h3>вы можете <a href="/pageSignIn.html">Войти!</a></h3>
</div>
<label>Email</label>
<div class="input-group mb-3 border-bottom">
<span class="input-group-text border-0 bg-white" id="basic-addon1"><img src="/src/icons/icons_sigh/envelope.svg" alt=""></span>
<input type="text" class="form-control border-0 placeholder-class" placeholder="Введите вашу почту" aria-label="Email" aria-describedby="basic-addon1">
</div>
<label>Username</label>
<div class="input-group mb-3 border-bottom">
<span class="input-group-text border-0 bg-white" id="basic-addon1"><img src="/src/icons/icons_sigh/person.svg" alt=""></span>
<input type="text" class="form-control border-0 placeholder-class" placeholder="Введите ваше имя" aria-label="Username" aria-describedby="basic-addon1">
</div>
<label>Password</label>
<div class="input-group mb-3 border-bottom">
<span class="input-group-text border-0 bg-white" id="basic-addon1"> <img src="/src/icons/icons_sigh/lock.svg" alt=""></span>
<input type="text" class="form-control border-0 placeholder-class" placeholder="Введите ваш пароль" aria-label="Password" aria-describedby="basic-addon1">
</div>
<label>Confirm Password</label>
<div class="input-group mb-3 border-bottom">
<span class="input-group-text border-0 bg-white" id="basic-addon1"><img src="/src/icons/icons_sigh/lock-fill.svg" alt=""></span>
<input type="text" class="form-control border-0 placeholder-class" placeholder="Повторите ваш пароль" aria-label="ConfPassword" aria-describedby="basic-addon1">
</div>
<button class="btn-sign btn btn-lg mt-5 shadow border text-light"><a href="/index.html" style="text-decoration: none; color: inherit">Регистрация</a></button>
</form>
</div>
</div>
</div>
</div>
<div class="col-auto d-none d-xl-block">
<img class="picture-sigh" src="/src/banners/cover.png" alt="" width="70%">
</div>
</div>
</main>
</body>
</html>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-envelope" viewBox="0 0 16 16">
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V4Zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1H2Zm13 2.383-4.708 2.825L15 11.105V5.383Zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741ZM1 11.105l4.708-2.897L1 5.383v5.722Z"/>
</svg>

After

Width:  |  Height:  |  Size: 438 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-lock-fill" viewBox="0 0 16 16">
<path d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2z"/>
</svg>

After

Width:  |  Height:  |  Size: 273 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-lock" viewBox="0 0 16 16">
<path d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM5 8h6a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 337 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person" viewBox="0 0 16 16">
<path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/>
</svg>

After

Width:  |  Height:  |  Size: 387 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
<path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
</svg>

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,313 @@
header nav {
background-color: #181818;
margin-bottom: 1%;
}
@media (max-width: 768px) {
header nav {
height: 90px;
}
.panel-col {
display: flex;
flex-direction: row;
justify-content: center;
}
}
#body tr:hover {
cursor: pointer;
}
@media (max-width: 766px) {
.banner-main {
width: 30vw;
}
}
@media (max-width: 368px) {
.panel-col {
display: flex;
flex-direction: column;
}
.banner-main {
width: auto;
}
}
.banner-main {
border-radius: 10px;
background: #A59672;
margin-top: 20px;
height: relative;
margin-right: 10px;
}
header nav a:hover {
text-decoration: underline;
}
.about-us-link {
align-content: start;
margin-left: 0;
padding-left: 0;
}
.btn-rectangle-white {
color: #3D4F64;
font-family: Montserrat;
padding: 1ex;
padding-left: 5ex;
padding-right: 5ex;
border-radius: 2px;
border: 1px solid #3D4F64;
background: #FFF;
}
.btn-rectangle {
color: #ffffff;
font-family: Montserrat;
padding: 1ex;
padding-left: 5ex;
padding-right: 5ex;
border-radius: 2px;
border: 1px solid #3D4F64;
background: #3E5646;
}
.badge {
background: #3E5646;
}
.row-of-inter {
margin-left: 10%;
margin-top: 5%;
}
.row-of-pictures {
text-align: center;
}
.picture-sigh {
display: inline-block;
}
menu {
margin: 100px, 100px;
padding: 10%, 10%;
}
.d-inline-block {
border-radius: 20%;
}
.col-of-about {
background-color: #3E5646;
}
.table {
border-spacing: 1px;
}
@media (max-width: 310px) {
.font-basket {
font-size: 13px;
}
}
.text-about-us {
text-align: justify;
padding: auto;
}
card-description-text {
text-align: justify;
padding: auto;
}
.card {
border: #ffffff;
transition: 0.3s;
}
.input-number {
width: 40px;
}
.btn-catalog {
background: #3E5646;
width: 100%;
padding-bottom: 4px;
padding-top: 4px;
font-size: small;
border: #3E5646;
}
.btn-catalog:hover,
.btn-sign:hover,
.btn-card,
.btn-rectangle:hover {
background: #2b3b30;
}
.quantity-goods {
width: relative;
}
.btn-catalog.btn.btn-primary:active,
.btn-sign.btn.btn-lg.mt-5.shadow.border.text-light:active,
.btn-card:active,
.btn.btn-rectangle:active {
background: #2b3b30;
}
.btn-card {
background: #887A57E0;
width: 25%;
padding: 20px;
}
.card-body {
margin-top: 10%;
padding: 0;
}
.card-text {
margin-top: 0;
padding: auto;
}
.card-description {
background: #3E5646;
}
.btn-sign {
width: 100%;
background: #3E5646;
border-radius: 25px;
padding-left: 8%;
padding-right: 8%;
border: #3E5646;
}
footer {
background-color: #181818;
height: 80px;
color: #ffffff;
padding: 2ex;
}
@media (max-width : 376px) {
footer {
height: 80px;
}
}
.counter {
height: 25px;
flex-shrink: 0;
border-radius: 2px;
border: 1px solid #C0C0C0;
background: #FFF;
}
.counter-btn {
width: 24.567px;
height: 25px;
flex-shrink: 0;
border-radius: 2px 0px 0px 2px;
background: #3D4F64;
}
@media (max-width : 376px) {
.placeholder-class {
font-size: 4vw;
}
}
@media (max-width:768px) {
.col-bott {
margin-top: 10px;
}
.banner-text {
font-size: 24px;
}
}
@media (max-width:768px) {
.banner-text.ms-2 {
font-size: 13px;
}
}
.banner-text {
color: #FFF;
font-family: Inria Serif;
font-size: 1.3vw;
font-style: normal;
font-weight: 400;
line-height: 149.4%;
}
.card-title {
font-size: 15px;
}
.card-text {
font-size: small;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.25em;
}
h3 {
font-size: 1.1em;
}

View File

@ -0,0 +1,26 @@
<?php
if( isset( $_POST['my_file_upload'] ) ){
// ВАЖНО! тут должны быть все проверки безопасности передавемых файлов и вывести ошибки если нужно
$uploaddir = './'; // . - текущая папка где находится submit.php
// cоздадим папку если её нет
if( ! is_dir( $uploaddir ) ) mkdir( $uploaddir, 0777 );
$files = $_FILES; // полученные файлы
$done_files = array();
// переместим файлы из временной директории в указанную
foreach( $files as $file ){
$file_name = $file['name'];
if( move_uploaded_file( $file['tmp_name'], "$uploaddir/$file_name" ) ){
$done_files[] = realpath( "$uploaddir/$file_name" );
}
}
$data = $done_files ? array('files' => $done_files ) : array('error' => 'Ошибка загрузки файлов.');
die( json_encode( $data ) );
}

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
})

BIN
3_Lab/~$Отчет.doc Normal file

Binary file not shown.

BIN
3_Lab/Отчет.doc Normal file

Binary file not shown.

24
4_Lab/4_Lab/.eslintrc.cjs Normal file
View File

@ -0,0 +1,24 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'airbnb-base',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parserOptions: { ecmaVersion: 12, sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
'indent': 'off',
'no-console': 'off',
'arrow-body-style': 'off',
'implicit-arrow-linebreak': 'off',
},
}

24
4_Lab/4_Lab/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

29
4_Lab/4_Lab/README.md Normal file
View File

@ -0,0 +1,29 @@
#### Окружение:
- nodejs 18;
- VSCode;
- ESLint плагин для VSCode;
- для отладки необходимы бразузеры Chrome или Edge.
#### Создание пустого проекта:
```commandline
npm create vite@latest ./ -- --template react
```
#### Установка зависимостей:
```commandline
npm install
```
#### Запуск проекта:
```commandline
npm run dev
```
#### Сборка проекта:
```commandline
npm run build
```

14
4_Lab/4_Lab/index.html Normal file
View File

@ -0,0 +1,14 @@
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BookCamp</title>
</head>
<body>
<div id="root" class="h-100 d-flex flex-column"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

14
4_Lab/4_Lab/jsconfig.json Normal file
View File

@ -0,0 +1,14 @@
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Node",
"target": "ES2020",
"jsx": "react",
"strictNullChecks": true,
"strictFunctionTypes": true
},
"exclude": [
"node_modules",
"**/node_modules/*"
]
}

4344
4_Lab/4_Lab/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

32
4_Lab/4_Lab/package.json Normal file
View File

@ -0,0 +1,32 @@
{
"name": "lec4",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.18.0",
"bootstrap": "^5.3.2",
"react-bootstrap": "^2.9.1",
"react-bootstrap-icons": "^1.10.3",
"prop-types": "^15.8.1"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@vitejs/plugin-react": "^4.0.3",
"eslint": "^8.45.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"vite": "^4.4.5"
}
}

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cart2" viewBox="0 0 16 16">
<path d="M0 2.5A.5.5 0 0 1 .5 2H2a.5.5 0 0 1 .485.379L2.89 4H14.5a.5.5 0 0 1 .485.621l-1.5 6A.5.5 0 0 1 13 11H4a.5.5 0 0 1-.485-.379L1.61 3H.5a.5.5 0 0 1-.5-.5zM3.14 5l1.25 5h8.22l1.25-5H3.14zM5 13a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-2 1a2 2 0 1 1 4 0 2 2 0 0 1-4 0zm9-1a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-2 1a2 2 0 1 1 4 0 2 2 0 0 1-4 0z"/>
</svg>

After

Width:  |  Height:  |  Size: 463 B

0
4_Lab/4_Lab/src/App.css Normal file
View File

24
4_Lab/4_Lab/src/App.jsx Normal file
View File

@ -0,0 +1,24 @@
import PropTypes from 'prop-types';
import { Container } from 'react-bootstrap';
import { Outlet } from 'react-router-dom';
import './App.css';
import Footer from './components/footer/Footer.jsx';
import Navigation from './components/navigation/Navigation.jsx';
const App = ({ routes }) => {
return (
<>
<Navigation routes={routes}></Navigation>
<Container className='p-2' as="main" fluid>
<Outlet />
</Container>
<Footer />
</>
);
};
App.propTypes = {
routes: PropTypes.array,
};
export default App;

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-envelope" viewBox="0 0 16 16">
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V4Zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1H2Zm13 2.383-4.708 2.825L15 11.105V5.383Zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741ZM1 11.105l4.708-2.897L1 5.383v5.722Z"/>
</svg>

After

Width:  |  Height:  |  Size: 438 B

Some files were not shown because too many files have changed in this diff Show More