This commit is contained in:
Aleksey Filippov 2024-10-09 15:13:24 +04:00
commit 55c7a7a9f9
26 changed files with 8058 additions and 0 deletions

2
.eslintignore Normal file
View File

@ -0,0 +1,2 @@
node_modules
dist

16
.eslintrc.json Normal file
View File

@ -0,0 +1,16 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["airbnb-base", "prettier"],
"plugins": ["prettier"],
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"rules": {
"prettier/prettier": "error",
"no-console": "off"
}
}

42
.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
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
View File

@ -0,0 +1,7 @@
{
"tabWidth": 4,
"singleQuote": false,
"printWidth": 120,
"trailingComma": "es5",
"useTabs": false
}

8
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"recommendations": [
"usernamehw.errorlens",
"AndersEAndersen.html-class-suggestions",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}

18
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
"configurations": [
{
"type": "chrome",
"name": "Debug",
"request": "launch",
"url": "http://localhost:5173"
},
{
"type": "node",
"name": "Start",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "start"],
"console": "integratedTerminal"
}
]
}

40
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,40 @@
{
"files.autoSave": "onFocusChange",
"files.eol": "\n",
"editor.detectIndentation": false,
"editor.formatOnType": false,
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"editor.tabSize": 4,
"editor.insertSpaces": true,
"editor.accessibilitySupport": "off",
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.sortImports": "explicit"
},
"editor.snippetSuggestions": "bottom",
"debug.toolBarLocation": "commandCenter",
"debug.showVariableTypes": true,
"errorLens.gutterIconsEnabled": true,
"errorLens.messageEnabled": false,
"prettier.tabWidth": 4,
"prettier.singleQuote": false,
"prettier.printWidth": 120,
"prettier.trailingComma": "es5",
"prettier.useTabs": false,
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}

BIN
assets/banner1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 KiB

BIN
assets/banner2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 KiB

BIN
assets/banner3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 KiB

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

8
css/banner.css Normal file
View File

@ -0,0 +1,8 @@
#banner {
margin: 5px;
}
#banner img {
border: 1px solid #3c3c3f;
border-radius: 5px;
}

35
css/style.css Normal file
View File

@ -0,0 +1,35 @@
header nav {
background-color: #3c3c3c;
}
@media (min-width: 768px) {
header nav {
height: 64px;
}
}
header nav a:hover {
text-decoration: underline;
}
footer {
background-color: #9c9c9c;
height: 64px;
color: #ffffff;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.25em;
}
h3 {
font-size: 1.1em;
}
.w-40 {
width: 40% !important;
}

118
index.html Normal file
View File

@ -0,0 +1,118 @@
<html lang="ru">
<head>
<meta charset="utf-8" />
<title>Моя страница</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script type="module" src="./node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<link href="./node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="./node_modules/bootstrap-icons/font/bootstrap-icons.min.css" rel="stylesheet" />
<link rel="stylesheet" href="./css/style.css" />
</head>
<body class="h-100 d-flex flex-column">
<header>
<nav class="navbar navbar-expand-md navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<i class="bi bi-app"></i>
Мой сайт
</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" id="navbarNav">
<div class="navbar-nav">
<a class="nav-link active" href="./index.html">Главная страница</a>
<a class="nav-link" href="./page2.html">Вторая страница</a>
<a class="nav-link" href="./page3.html">Третья страница</a>
<a class="nav-link" href="./page-js.html">JavaScript</a>
</div>
</div>
</div>
</nav>
</header>
<div id="banner" class="carousel carousel-dark slide">
<div class="carousel-indicators">
<button
type="button"
data-bs-target="#banner"
data-bs-slide-to="0"
aria-current="true"
aria-label="Slide 1"
></button>
<button type="button" data-bs-target="#banner" data-bs-slide-to="1" aria-label="Slide 2"></button>
<button type="button" data-bs-target="#banner" data-bs-slide-to="2" aria-label="Slide 3"></button>
</div>
<div class="carousel-inner">
<div class="carousel-item" data-interval="10000">
<img class="d-block w-100" src="/assets/banner1.png" alt="banner1" />
<div class="carousel-caption d-none d-md-block">
<h5>First slide label</h5>
<p>Some representative placeholder content for the first slide.</p>
</div>
</div>
<div class="carousel-item" data-dark="true">
<img class="d-block w-100" src="/assets/banner2.png" alt="banner2" />
<div class="carousel-caption d-none d-md-block">
<h5>Second slide label</h5>
<p>Some representative placeholder content for the second slide.</p>
</div>
</div>
<div class="carousel-item" data-dark="true">
<img class="d-block w-100" src="/assets/banner3.png" alt="banner3" />
<div class="carousel-caption d-none d-md-block">
<h5>Third slide label</h5>
<p>Some representative placeholder content for the third slide.</p>
</div>
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#banner" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#banner" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
<main class="container-fluid p-3">
<h1>Пример web-страницы.</h1>
<h2>1. Структурные элементы</h2>
<p>
<b>Полужирное начертание <i>курсив</i></b>
</p>
<p>Абзац 2 <a href="page2.html">Ссылка</a></p>
<h3>1.1. Списки</h3>
<p>Список маркированный:</p>
<ul>
<li><a href="page2.html" target="_blank">Элемент списка 1</a></li>
<li>Элемент списка 2</li>
<li>...</li>
</ul>
<p>Список нумерованный:</p>
<ol>
<li>Элемент списка 1</li>
<li>Элемент списка 2</li>
<li>...</li>
</ol>
</main>
<footer class="footer mt-auto d-flex flex-shrink-0 justify-content-center align-items-center">
Автор, 2022
</footer>
<script type="module">
import myBanner from "./js/banner";
document.addEventListener("DOMContentLoaded", () => {
myBanner("#banner");
});
</script>
</body>
</html>

106
js/banner.js Normal file
View File

@ -0,0 +1,106 @@
// Модуль для смены изображения в баннере по таймеру
// Подключить CSS, который относится к данному модулю при подключении модуля
import "../css/banner.css";
// указывается блок, в котором будет баннер
// блок должен содержать изображения
function myBanner(root) {
console.info("Baner logic successfully loaded");
// Константы
const DARK_CLASS = "carousel-dark";
const TIMEOUT_ATTR = "data-interval";
const THEME_ATTR = "data-dark";
const TIMEOUT = 5000;
// Переменная для хранения текущего ID таймера
let timerId;
// Получение всех необходимых элементов внутри блока с баннером
// Блок с баннерами
const bannerRoot = document.querySelector(root);
// Баннеры
const banners = Array.from(document.querySelectorAll(`${root} .carousel-item`));
// Интерактивные элементы для переключения баннеров, в том числе надписи
const indicators = Array.from(document.querySelectorAll(`${root} .carousel-indicators button`));
const controls = Array.from(document.querySelectorAll(".carousel-control-prev, .carousel-control-next"));
// Последний индекс для баннеров
const LAST_INDEX = banners.length - 1;
// Получить сведения о баннере для показа и его настройках
const getBannerConfig = () => {
// Получить текущий баннер
const currentElement = banners.find((banner) => banner.classList.contains("active"));
// Получить индекс текущего баннера
const hideIndex = currentElement === undefined ? LAST_INDEX : banners.indexOf(currentElement);
// Получить индекс следующего баннера
const showIndex = hideIndex === LAST_INDEX ? 0 : hideIndex + 1;
// Получить параметр времени показа баннера (значение атрибута data-interval)
const interval = parseInt(banners[showIndex].getAttribute(TIMEOUT_ATTR) ?? TIMEOUT, 10);
// Получить параметр темы надписи баннера (значение атрибута data-dark)
const isDark = banners[showIndex].getAttribute(THEME_ATTR);
// Если требуется темная тема, то добавить класс carousel-dark к блоку баннеров,
// иначе удалить его
if (isDark) {
bannerRoot.classList.add(DARK_CLASS);
} else {
bannerRoot.classList.remove(DARK_CLASS);
}
// Вывести отладочные сведения
console.debug(banners[showIndex], interval, hideIndex, showIndex);
// Возврат объекта
return { hideIndex, showIndex, interval };
};
// Функция для смены баннера
const changeBanner = () => {
// Получить сведения о текущем и следующем баннере
const config = getBannerConfig();
// Скрыть текущий баннер и его надпись
banners[config.hideIndex].classList.remove("active");
indicators[config.hideIndex].classList.remove("active");
// Показать следующий баннер и его надпись
banners[config.showIndex].classList.add("active");
indicators[config.showIndex].classList.add("active");
// Вывеси сообщение об автоматической смене баннера
console.info("Banner changed automatically");
// Установка таймера на n секунд, после чего функция будет запущена повторно
timerId = setTimeout(changeBanner, config.interval);
};
// Функция для сброса текущего таймера и создания нового с учетом настроек баннера,
// на который пользователь перешел с помощью элементов управления
const resetTimer = () => {
// Если таймер с указанным ID существует, то удалить его
if (timerId) {
clearTimeout(timerId);
}
// Получить сведения о текущем и следующем баннере
const config = getBannerConfig();
// Вывеси сообщение о ручной смене баннера (пользователь нажал на кнопку)
console.info("Banner changed manually");
// Установка таймера на n секунд, после чего функция будет запущена повторно
timerId = setTimeout(changeBanner, config.interval);
};
// Скрываем все баннеры
banners.forEach((banner) => banner.classList.remove("active"));
// Установка обработчика дополнительных событий для события click элементов ручного переключения баннеров
[...indicators, ...controls].forEach((element) => element.addEventListener("click", () => resetTimer(timerId)));
// Показываем первый баннер, после чего будет создан цикл переключений через вызов таймеров
changeBanner();
}
// Экспорт функции myBanner
export default myBanner;

0
js/main.js Normal file
View File

32
js/validation.js Normal file
View File

@ -0,0 +1,32 @@
// Модуль используется для валидации форма на странице
// Функция для проверки элементов управления формы на заполненность и корректность
const checkForm = (event) => {
// Получаем ссылку на форму
const form = event.target;
// https://learn.javascript.ru/bubbling-and-capturing
// Если какой-либо элемент формы не заполнен или заполнен с ошибками, то
if (!form.checkValidity()) {
// Отменяем действие по умолчанию
event.preventDefault();
// Предотвратить всплытие события
// Когда на элементе происходит событие, обработчики сначала срабатывают на нём,
// потом на его родителе, затем выше и так далее, вверх по цепочке предков.
// event.stopPropagation();
}
// добавляет к форме класс was-validated
form.classList.add("was-validated");
};
// Функция для привязки обработчика событий
const myValidation = () => {
// Поиск всех форма с классом .needs-validation
const forms = document.querySelectorAll("form.needs-validation");
// Установка функции checkForm в качестве обработчика события submit
forms.forEach((form) => form.addEventListener("submit", checkForm));
};
// Экспорт функции myValidation
export default myValidation;

134
old/index.html Normal file
View File

@ -0,0 +1,134 @@
<!doctype html>
<html lang="ru" data-bs-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My site</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
/>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous"
/>
<link href="style.css" rel="stylesheet" />
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNav"
aria-controls="navbarNav"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" aria-disabled="true"><i class="bi bi-android"></i>Disabled</a>
</li>
</ul>
</div>
</div>
</nav>
<main class="container-fluid p-2">
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col">Handle</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td colspan="2">Larry the Bird</td>
<td>@twitter</td>
</tr>
</tbody>
</table>
<div class="d-flex flex-md-row flex-column justify-content-center mt-2 p-5">
<div class="card" style="width: 18rem">
<img src="..." class="card-img-top" alt="..." />
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">
Some quick example text to build on the card title and make up the bulk of the card's
content.
</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
<div class="card" style="width: 18rem">
<img src="..." class="card-img-top" alt="..." />
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">
Some quick example text to build on the card title and make up the bulk of the card's
content.
</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
<div class="card" style="width: 18rem">
<img src="..." class="card-img-top" alt="..." />
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">
Some quick example text to build on the card title and make up the bulk of the card's
content.
</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
</div>
</main>
<script
src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"
></script>
</body>
</html>

3
old/style.css Normal file
View File

@ -0,0 +1,3 @@
.card {
margin-right: 0.5em;
}

7081
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

26
package.json Normal file
View File

@ -0,0 +1,26 @@
{
"name": "int-prog",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "vite",
"serve": "http-server -p 3000 ./dist/",
"build": "vite build",
"prod": "npm-run-all build serve",
"lint": "eslint . --ext js --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
"bootstrap": "5.3.3",
"bootstrap-icons": "1.11.3"
},
"devDependencies": {
"http-server": "14.1.1",
"vite": "5.4.8",
"npm-run-all": "4.1.5",
"eslint": "8.57.1",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-prettier": "5.2.1"
}
}

92
page-js.html Normal file
View File

@ -0,0 +1,92 @@
<html lang="ru">
</html>
<head>
<meta charset="utf-8">
<title>Моя страница</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="module" src="./node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<link href="./node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="./node_modules/bootstrap-icons/font/bootstrap-icons.min.css" rel="stylesheet" />
<link rel="stylesheet" href="./css/style.css">
</head>
<body class="h-100 d-flex flex-column">
<header>
<nav class="navbar navbar-expand-md navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<i class="bi bi-app"></i>
Мой сайт
</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" id="navbarNav">
<div class="navbar-nav">
<a class="nav-link" href="./index.html">Главная страница</a>
<a class="nav-link" href="./page2.html">Вторая страница</a>
<a class="nav-link" href="./page3.html">Третья страница</a>
<a class="nav-link active" href="./page-js.html">JavaScript</a>
</div>
</div>
</div>
</nav>
</header>
<main class="container-fluid p-3">
</main>
<footer class="footer mt-auto d-flex flex-shrink-0 justify-content-center align-items-center">
Автор, 2022
</footer>
<script type="module">
function someFunc() {
return "world!";
}
const someFunc2 = function () {
return "asdasd";
}
const someFunc3 = () => "asdasd111";
const someFunc4 = (x, y) => x * y;
const TEST = `asdasd
asdasdasd
asdasdasd`;
const manufacturer = "lada";
const car = {
manufacturer,
speed: 10,
color: "red",
price: 1000.2,
print: () => `Color is`,
}
let x = "hello!";
console.log(x, someFunc(), someFunc2(), someFunc3(), someFunc4(3, 4));
x = 3;
console.log(`value is ${x} ${x * 2} price ${car.price}`, TEST, car, car.print());
let { speed, color, price } = car;
console.log(speed, color, price);
var arr = [1, 'asd', 'asd', false];
console.log(arr);
let arr1 = [1, 2, 3, 4];
let arr2 = ['a', 'b', 'c'];
let arr3 = [arr1, arr2];
console.log(arr3);
let func = (a, b, c, d) => a + b + c + d
console.log(func(...arr1))
</script>
</body>
</html>

80
page2.html Normal file
View File

@ -0,0 +1,80 @@
<html lang="ru">
<head>
<meta charset="utf-8" />
<title>Моя страница</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script type="module" src="./node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<link href="./node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="./node_modules/bootstrap-icons/font/bootstrap-icons.min.css" rel="stylesheet" />
<link rel="stylesheet" href="./css/style.css" />
</head>
<body class="h-100 d-flex flex-column">
<header>
<nav class="navbar navbar-expand-md navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<i class="bi bi-app"></i>
Мой сайт
</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" id="navbarNav">
<div class="navbar-nav">
<a class="nav-link" href="./index.html">Главная страница</a>
<a class="nav-link active" href="./page2.html">Вторая страница</a>
<a class="nav-link" href="./page3.html">Третья страница</a>
<a class="nav-link" href="./page-js.html">JavaScript</a>
</div>
</div>
</div>
</nav>
</header>
<main class="container-fluid p-3">
<p class="text-center">Вторая страница содержит пример рисунка (рис. 1) и таблицы (таб. 1).</p>
<div class="text-center">
<img src="./assets/logo.png" alt="logo" width="128" />
<br />
Рис. 1. Пример рисунка.
</div>
<div class="mt-3 row justify-content-center">
<table class="table table-bordered w-50">
<caption>
Таблица 1. Пример таблицы.
</caption>
<thead>
<tr>
<th class="w-25">Номер</th>
<th>ФИО</th>
<th class="w-25">Телефон</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Иванов</td>
<td>89999999999</td>
</tr>
<tr>
<td>2</td>
<td>Петров</td>
<td>89999999991</td>
</tr>
</tbody>
</table>
</div>
</main>
<footer class="footer mt-auto d-flex flex-shrink-0 justify-content-center align-items-center">
Автор, 2022
</footer>
</body>
</html>

175
page3.html Normal file
View File

@ -0,0 +1,175 @@
<html lang="ru">
<head>
<meta charset="utf-8" />
<title>Моя страница</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script type="module" src="./node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<link href="./node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="./node_modules/bootstrap-icons/font/bootstrap-icons.min.css" rel="stylesheet" />
<link rel="stylesheet" href="./css/style.css" />
</head>
<body class="h-100 d-flex flex-column">
<header>
<nav class="navbar navbar-expand-md navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<i class="bi bi-app"></i>
Мой сайт
</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" id="navbarNav">
<div class="navbar-nav">
<a class="nav-link" href="./index.html">Главная страница</a>
<a class="nav-link" href="./page2.html">Вторая страница</a>
<a class="nav-link active" href="./page3.html">Третья страница</a>
<a class="nav-link" href="./page-js.html">JavaScript</a>
</div>
</div>
</div>
</nav>
</header>
<main class="container-fluid p-3">
<div class="row justify-content-center">
<div class="text-center mb-2">
<h3 id="form-state"></h3>
</div>
<form class="col-md-6 m-0 needs-validation" action="./page3.html" method="get" novalidate>
<div class="mb-2">
<label class="form-label" for="lastname">Фамилия</label>
<input id="lastname" name="lastname" class="form-control" type="text" required />
<div class="valid-feedback">Фамилия заполнена</div>
<div class="invalid-feedback">Фамилия не заполнена</div>
</div>
<div class="mb-2">
<label class="form-label" for="firstname">Имя</label>
<input id="firstname" name="firstname" class="form-control" type="text" required />
</div>
<div class="mb-2">
<label class="form-label" for="email">E-mail</label>
<input
id="email"
name="email"
class="form-control"
type="email"
placeholder="name@example.ru"
required
/>
</div>
<div class="mb-2">
<label class="form-label" for="password">Пароль</label>
<input
id="password"
name="password"
class="form-control"
type="password"
autocomplete="off"
required
/>
</div>
<div class="mb-2">
<label class="form-label" for="date">Дата</label>
<input id="date" name="date" class="form-control" type="date" required />
</div>
<div class="mb-2">
<label class="form-label" for="disabled">Выключенный компонент</label>
<input
id="disabled"
name="disabled"
class="form-control"
type="text"
value="Некоторое значение"
disabled
/>
</div>
<div class="mb-2">
<label class="form-label" for="readonly">Компонент только для чтения</label>
<input
id="readonly"
name="readonly"
class="form-control"
type="text"
value="Некоторое значение"
readonly
/>
</div>
<div class="mb-2">
<label class="form-label" for="color">Выбор цвета</label>
<input id="color" name="color" type="color" class="form-control form-control-color" />
</div>
<div class="mb-2 d-md-flex flex-md-row">
<div class="form-check me-md-3">
<input class="form-check-input" id="checkbox1" name="checkbox1" type="checkbox" required />
<label class="form-check-label" for="checkbox1">Флажок 1</label>
</div>
<div class="form-check">
<input class="form-check-input" id="checkbox2" name="checkbox2" type="checkbox" />
<label class="form-check-label" for="checkbox2">Флажок 2</label>
</div>
</div>
<div class="mb-2 d-md-flex flex-md-row">
<div class="form-check me-md-3">
<input class="form-check-input" type="radio" name="radio-example" id="radio1" />
<label class="form-check-label" for="radio1">Переключатель 1</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="radio-example" id="radio2" />
<label class="form-check-label" for="radio2">Переключатель 2</label>
</div>
</div>
<div class="mb-2">
<select class="form-select" name="selected" required>
<option value="" selected>Выберите значение</option>
<option value="1">Один</option>
<option value="2">Два</option>
<option value="3">Три</option>
</select>
</div>
<div class="col-12 text-center">
<button class="btn btn-primary w-40 me-1" type="submit">Отправить</button>
<button class="btn btn-primary w-40" type="button" onclick="toggleNoValidate()">
Переключить novalidate
</button>
</div>
</form>
</div>
</main>
<footer class="footer mt-auto d-flex flex-shrink-0 justify-content-center align-items-center">
Автор, 2022
</footer>
<script type="module">
import myValidation from "./js/validation";
const VAL_ATTR = "novalidate";
const form = document.querySelector("form");
const state = document.getElementById("form-state");
const setFormState = () => {
state.innerText = `novalidate формы ${form.hasAttribute(VAL_ATTR) ? "включен" : "выключен"}`;
};
const toggleNoValidate = () => {
form.classList.remove("was-validated");
form.toggleAttribute(VAL_ATTR);
setFormState();
};
document.addEventListener("DOMContentLoaded", () => {
myValidation();
setFormState();
});
window.toggleNoValidate = toggleNoValidate;
</script>
</body>
</html>

19
readme.md Normal file
View File

@ -0,0 +1,19 @@
0. nvm for windows
https://github.com/coreybutler/nvm-windows/releases/download/1.1.12/nvm-setup.exe
nvm install lts
nvm use lts
1. Установка библиотек
npm install
2.1 Запуск в режиме для разработки
npm start
2.2 Запуск в режиме для использования
npm run prod

16
vite.config.js Normal file
View File

@ -0,0 +1,16 @@
import { resolve } from "path";
// eslint-disable-next-line import/no-extraneous-dependencies
import { defineConfig } from "vite";
export default defineConfig({
build: {
rollupOptions: {
input: {
main: resolve(__dirname, "index.html"),
page2: resolve(__dirname, "page2.html"),
page3: resolve(__dirname, "page3.html"),
pagejs: resolve(__dirname, "page-js.html"),
},
},
},
});