Compare commits
11 Commits
cdb7405b1f
...
lab4
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fa9e60bab | |||
| ae4a4e755f | |||
| 229187dd4e | |||
| 632835f834 | |||
| f7afa74bed | |||
| 205bb0f195 | |||
| 0ead01438a | |||
| 1940a8e172 | |||
| 801a6cac28 | |||
| 684c9d7675 | |||
| e0cf8ff04b |
@@ -1,2 +0,0 @@
|
||||
node_modules
|
||||
dist
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": ["airbnb-base", "prettier"],
|
||||
"plugins": ["prettier", "html"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 12,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"no-console": "off"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"singleQuote": false,
|
||||
"printWidth": 120,
|
||||
"trailingComma": "es5",
|
||||
"useTabs": false
|
||||
}
|
||||
119
basket.html
@@ -5,22 +5,77 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop basket</title>
|
||||
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<!-- Кастомные стили -->
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar .dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.navbar .dropdown .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* прижимаем футер вниз */
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1; /* растягивается, чтобы футер был внизу */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигация (как в main.html) -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<!-- ... та же навигация, что и в main.html ... -->
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="main.html">
|
||||
<img src="img/cyxaruk shop logo.jpg" alt="логотип" width="50" height="50" class="rounded-circle me-2">
|
||||
<span class="fw-bold">cyxaruk shop</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-list-ul me-1"></i>Каталог
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="contacts.html"><i class="bi bi-telephone me-1"></i>Контакты</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="likes.html"><i class="bi bi-heart me-1"></i>Избранное</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="basket.html"><i class="bi bi-cart me-1"></i>Корзина</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
|
||||
<main class="container my-4">
|
||||
<div class="text-center py-5">
|
||||
<div class="empty-basket text-center py-5">
|
||||
<h1 class="mb-4">Здесь будут лежать твои товары</h1>
|
||||
<p class="lead mb-4">А пока здесь так пусто...</p>
|
||||
<img src="img/sad1.jpg" alt="Пустая корзина" class="img-fluid rounded" style="max-height: 300px;">
|
||||
@@ -30,14 +85,50 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="basketContainer"></div>
|
||||
</main>
|
||||
|
||||
<!-- Подвал (как в main.html) -->
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<!-- ... тот же подвал, что и в main.html ... -->
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<a href="https://t.me/cyxarukShop" class="text-white me-3">
|
||||
<i class="bi bi-telegram fs-2"></i>
|
||||
</a>
|
||||
<span>Подпишитесь на нас в Telegram</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="https://www.avito.ru/..." class="text-white me-3">
|
||||
<i class="bi bi-shop-window fs-2"></i>
|
||||
</a>
|
||||
<span>Мы на Авито</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<h5>Контакты</h5>
|
||||
<p><i class="bi bi-telephone me-2"></i>89876320523</p>
|
||||
<p><i class="bi bi-geo-alt me-2"></i>Ulyanovsk, Russia</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<script type="module">
|
||||
import { Model } from '/components/basket/model.js';
|
||||
import { View } from '/components/basket/view.js';
|
||||
import { Controller } from '/components/basket/controller.js';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (document.getElementById('basketContainer') || document.getElementById('productsContainer')) {
|
||||
const model = new Model();
|
||||
const view = new View();
|
||||
new Controller(model, view);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
423
catalog.html
@@ -5,64 +5,158 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop catalog</title>
|
||||
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<!-- Кастомные стили -->
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
<style>
|
||||
.like-btn.liked {
|
||||
color: #000000 !important;
|
||||
border-color: #dc3545 !important;
|
||||
}
|
||||
.like-btn.liked i {
|
||||
color: #dc3545 !important;
|
||||
}
|
||||
/* Черная оконтовка при наведении на нажатую кнопку */
|
||||
.like-btn.liked:hover i {
|
||||
text-shadow: 0 0 2px #000000,
|
||||
0 0 2px #000000,
|
||||
0 0 2px #000000;
|
||||
}
|
||||
/* Плавное изменение */
|
||||
.like-btn i {
|
||||
transition: text-shadow 0.2s ease;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигация (как в main.html) -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<!-- ... та же навигация, что и в main.html ... -->
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="main.html">
|
||||
<img src="img/cyxaruk shop logo.jpg" alt="логотип" width="50" height="50" class="rounded-circle me-2">
|
||||
<span class="fw-bold">cyxaruk shop</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-list-ul me-1"></i>Каталог
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="contacts.html"><i class="bi bi-telephone me-1"></i>Контакты</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="likes.html"><i class="bi bi-heart me-1"></i>Избранное</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="basket.html"><i class="bi bi-cart me-1"></i>Корзина</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar .dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.navbar .dropdown .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<main class="container my-4">
|
||||
<h1 class="text-center mb-4">Каталог товаров</h1>
|
||||
|
||||
<!-- Форма добавления товара -->
|
||||
<div class="card mb-4 border-0 shadow-sm">
|
||||
<div class="card-header" style="background-color: #00264d; color: white;">
|
||||
<h5 class="mb-0"><i class="bi bi-plus-circle me-2"></i>Добавить новый товар</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="addProductForm" class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="productName" class="form-label">Название товара</label>
|
||||
<input type="text" class="form-control" id="productName" required>
|
||||
<div class="accordion" id="accordionExample">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingOne">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" style="background-color: #b0d8ff;" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
Добавить товар
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body">
|
||||
<div class="card mb-4 border-0 shadow">
|
||||
<div class="card-body">
|
||||
<form id="addProductForm" class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="productName" class="form-label">Название товара</label>
|
||||
<input type="text" class="form-control" id="productName" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="productPrice" class="form-label">Цена</label>
|
||||
<input type="text" class="form-control" id="productPrice" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="productCategory" class="form-label">Категория</label>
|
||||
<select class="form-select" id="productCategory" required>
|
||||
<option value="">Выберите категорию</option>
|
||||
<option value="1">Для мужчин</option>
|
||||
<option value="2">Для женщин</option>
|
||||
<option value="3">Унисекс</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="productCondition" class="form-label">Состояние</label>
|
||||
<select class="form-select" id="productCondition" required>
|
||||
<option value="">Выберите состояние</option>
|
||||
<option value="1">Новый</option>
|
||||
<option value="2">Б/У</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="productDescription" class="form-label">Описание</label>
|
||||
<textarea class="form-control" id="productDescription" rows="3" required></textarea>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="productImage" class="form-label">Ссылка на изображение</label>
|
||||
<input type="text" class="form-control" id="productImage" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-check-circle me-2"></i>Добавить товар
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="productPrice" class="form-label">Цена</label>
|
||||
<input type="text" class="form-control" id="productPrice" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="productDescription" class="form-label">Описание</label>
|
||||
<textarea class="form-control" id="productDescription" rows="3" required></textarea>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="productImage" class="form-label">Ссылка на изображение</label>
|
||||
<input type="text" class="form-control" id="productImage" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-check-circle me-2"></i>Добавить товар
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 class="text-center mb-4 mt-2">Каталог товаров</h1>
|
||||
<!-- Карточки товаров -->
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4" id="productsContainer">
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-5" id="productsContainer">
|
||||
<!-- Карточка товара 1 -->
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="img/stonik.jpg" class="card-img-top" alt="Stone Island">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Stone Island</h5>
|
||||
<h4 class="card-title">Stone Island</h4>
|
||||
<p class="card-text">super idol rovny pacan, groza rayona, mother's modnik, патч на месте</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">men</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">new</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
@@ -72,7 +166,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
@@ -83,35 +177,219 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Остальные товары аналогично -->
|
||||
<!-- Карточка товара 2 -->
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="img/adidas.jpg" class="card-img-top" alt="Adidas">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Adidas</h5>
|
||||
<p class="card-text">sportik, street, baskemtball, air, old school</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">men</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">wu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted">$19.99</span>
|
||||
<button class="btn btn-sm" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-cart-plus me-1"></i>В корзину
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-share"></i> Поделиться
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Карточка товара 3 -->
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="img/napapisaj.jpg" class="card-img-top" alt="Napapisaj">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Napapisaj</h5>
|
||||
<p class="card-text">super idol rovny pacan, groza rayona, mother's modnik, +rep from brothers</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">men</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">wu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted">$1499.99</span>
|
||||
<button class="btn btn-sm" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-cart-plus me-1"></i>В корзину
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-share"></i> Поделиться
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Карточка товара 4 -->
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="img/lacoste.png" class="card-img-top" alt="Lacoste">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Lacoste</h5>
|
||||
<p class="card-text">style, nice, mother's modnik, cotton, krokodil</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">uni</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">wu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted">$399.99</span>
|
||||
<button class="btn btn-sm" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-cart-plus me-1"></i>В корзину
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-share"></i> Поделиться
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Карточка товара 5 -->
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="img/samba.png" class="card-img-top" alt="Samba">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Samba</h5>
|
||||
<p class="card-text">super idol rovny pacan, groza rayona, mother's modnik, +rep from brothers</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">women</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">new</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted">$449.99</span>
|
||||
<button class="btn btn-sm" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-cart-plus me-1"></i>В корзину
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-share"></i> Поделиться
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Подвал (как в main.html) -->
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<!-- ... тот же подвал, что и в main.html ... -->
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<a href="https://t.me/cyxarukShop" class="text-white me-3">
|
||||
<i class="bi bi-telegram fs-2"></i>
|
||||
</a>
|
||||
<span>Подпишитесь на нас в Telegram</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="https://www.avito.ru/..." class="text-white me-3">
|
||||
<i class="bi bi-shop-window fs-2"></i>
|
||||
</a>
|
||||
<span>Мы на Авито</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<h5>Контакты</h5>
|
||||
<p><i class="bi bi-telephone me-2"></i>89876320523</p>
|
||||
<p><i class="bi bi-geo-alt me-2"></i>Ulyanovsk, Russia</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Скрипт для добавления товаров -->
|
||||
<script>
|
||||
document.getElementById('addProductForm').addEventListener('submit', function(e) {
|
||||
document.getElementById("addProductForm").addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const name = document.getElementById('productName').value;
|
||||
const price = document.getElementById('productPrice').value;
|
||||
const description = document.getElementById('productDescription').value;
|
||||
const image = document.getElementById('productImage').value;
|
||||
|
||||
const name = document.getElementById("productName").value;
|
||||
const price = document.getElementById("productPrice").value;
|
||||
const category = document.getElementById("productCategory").value;
|
||||
const condition = document.getElementById("productCondition").value;
|
||||
const description = document.getElementById("productDescription").value;
|
||||
const image = document.getElementById("productImage").value;
|
||||
|
||||
// Получаем текстовые значения для отображения
|
||||
const categoryText = document.getElementById("productCategory").options[document.getElementById("productCategory").selectedIndex].text;
|
||||
const conditionText = document.getElementById("productCondition").options[document.getElementById("productCondition").selectedIndex].text;
|
||||
|
||||
const productCard = `
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="${image}" class="card-img-top" alt="${name}">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">${name}</h5>
|
||||
<p class="card-text">${description}</p>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">${categoryText}</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">${conditionText}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
@@ -121,7 +399,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
@@ -132,10 +410,41 @@
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('productsContainer').insertAdjacentHTML('beforeend', productCard);
|
||||
|
||||
document.getElementById("productsContainer").insertAdjacentHTML("beforeend", productCard);
|
||||
this.reset();
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<script type="module">
|
||||
import { LikesModel } from '/components/likes/model.js';
|
||||
import { LikesView } from '/components/likes/view.js';
|
||||
import { LikesController } from '/components/likes/controller.js';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (document.getElementById('productsContainer')) {
|
||||
const likesModel = new LikesModel();
|
||||
const likesView = new LikesView();
|
||||
new LikesController(likesModel, likesView);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="module">
|
||||
import { Model } from '/components/basket/model.js';
|
||||
import { View } from '/components/basket/view.js';
|
||||
import { Controller } from '/components/basket/controller.js';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (document.getElementById('basketContainer') || document.getElementById('productsContainer')) {
|
||||
const model = new Model();
|
||||
const view = new View();
|
||||
new Controller(model, view);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
133
components/basket/controller.js
Normal file
@@ -0,0 +1,133 @@
|
||||
// controller.js
|
||||
export class Controller {
|
||||
constructor(model, view) {
|
||||
this.model = model;
|
||||
this.view = view;
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
// Для страницы корзины
|
||||
if (window.location.pathname.includes('basket.html')) {
|
||||
await this.loadBasket();
|
||||
this.setupBasketEventListeners();
|
||||
}
|
||||
|
||||
// Для страницы каталога
|
||||
if (window.location.pathname.includes('catalog.html')) {
|
||||
this.setupCatalogEventListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Загрузить и отобразить корзину
|
||||
async loadBasket() {
|
||||
const basketItems = await this.model.getBasketItems();
|
||||
this.view.showBasket(basketItems);
|
||||
}
|
||||
|
||||
// Настройка обработчиков событий для корзины
|
||||
setupBasketEventListeners() {
|
||||
document.addEventListener('click', async (e) => {
|
||||
const basketItem = e.target.closest('.basket-item');
|
||||
if (!basketItem) return;
|
||||
|
||||
const productId = basketItem.dataset.id;
|
||||
|
||||
// Удаление товара
|
||||
if (e.target.closest('.remove-btn')) {
|
||||
await this.model.removeFromBasket(productId);
|
||||
this.view.showNotification('Товар удален из корзины');
|
||||
await this.loadBasket();
|
||||
}
|
||||
|
||||
// Увеличение количества
|
||||
if (e.target.closest('.increase-btn')) {
|
||||
const quantityInput = basketItem.querySelector('.quantity-input');
|
||||
const newQuantity = parseInt(quantityInput.value) + 1;
|
||||
quantityInput.value = newQuantity;
|
||||
await this.model.updateBasketItem(productId, newQuantity);
|
||||
await this.loadBasket();
|
||||
}
|
||||
|
||||
// Уменьшение количества
|
||||
if (e.target.closest('.decrease-btn')) {
|
||||
const quantityInput = basketItem.querySelector('.quantity-input');
|
||||
let newQuantity = parseInt(quantityInput.value) - 1;
|
||||
if (newQuantity < 1) newQuantity = 1;
|
||||
quantityInput.value = newQuantity;
|
||||
await this.model.updateBasketItem(productId, newQuantity);
|
||||
await this.loadBasket();
|
||||
}
|
||||
});
|
||||
|
||||
// Обработка изменения количества через input
|
||||
document.addEventListener('change', async (e) => {
|
||||
if (e.target.classList.contains('quantity-input')) {
|
||||
const basketItem = e.target.closest('.basket-item');
|
||||
const productId = basketItem.dataset.id;
|
||||
const newQuantity = parseInt(e.target.value) || 1;
|
||||
|
||||
if (newQuantity < 1) {
|
||||
e.target.value = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
await this.model.updateBasketItem(productId, newQuantity);
|
||||
await this.loadBasket();
|
||||
}
|
||||
});
|
||||
|
||||
// Оформление заказа
|
||||
document.addEventListener('click', async (e) => {
|
||||
if (e.target.id === 'checkoutBtn') {
|
||||
const basketItems = await this.model.getBasketItems();
|
||||
if (basketItems.length === 0) {
|
||||
this.view.showNotification('Корзина пуста', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
this.view.showNotification('Заказ оформлен! Спасибо за покупку!');
|
||||
await this.model.clearBasket();
|
||||
await this.loadBasket();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Настройка обработчиков событий для каталога
|
||||
setupCatalogEventListeners() {
|
||||
document.addEventListener('click', async (e) => {
|
||||
if (e.target.closest('.btn') && e.target.closest('.btn').textContent.includes('В корзину')) {
|
||||
const card = e.target.closest('.card');
|
||||
const product = this.extractProductData(card);
|
||||
|
||||
if (product) {
|
||||
await this.model.addToBasket(product);
|
||||
this.view.showNotification('Товар добавлен в корзину!');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
extractProductData(card) {
|
||||
try {
|
||||
const name = card.querySelector('.card-title').textContent;
|
||||
const priceText = card.querySelector('.text-muted').textContent.replace('$', '');
|
||||
const description = card.querySelector('.card-text').textContent;
|
||||
const image = card.querySelector('img').src;
|
||||
|
||||
// Генерируем ID на основе содержимого карточки
|
||||
const id = btoa(`${name}-${priceText}`).substring(0, 8);
|
||||
|
||||
return {
|
||||
id: id,
|
||||
name: name.trim(),
|
||||
price: parseFloat(priceText),
|
||||
description: description.trim(),
|
||||
image: image
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Ошибка при извлечении данных товара:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
components/basket/model.js
Normal file
@@ -0,0 +1,118 @@
|
||||
// model.js
|
||||
export class Model {
|
||||
constructor() {
|
||||
this.apiUrl = 'http://localhost:3000';
|
||||
}
|
||||
|
||||
async request(url, options = {}) {
|
||||
try {
|
||||
const response = await fetch(`${this.apiUrl}${url}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Request failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getBasketItems() {
|
||||
try {
|
||||
return await this.request('/basket');
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении корзины:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Добавить товар в корзину
|
||||
async addToBasket(product) {
|
||||
try {
|
||||
// Проверяем, есть ли товар уже в корзине
|
||||
const basketItems = await this.getBasketItems();
|
||||
const existingItem = basketItems.find(item => item.id === product.id);
|
||||
|
||||
if (existingItem) {
|
||||
// Если товар уже есть, увеличиваем количество
|
||||
await this.updateBasketItem(product.id, existingItem.quantity + 1);
|
||||
} else {
|
||||
// Если товара нет, добавляем новый
|
||||
const basketItem = {
|
||||
...product,
|
||||
quantity: 1,
|
||||
addedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
const response = await fetch(`${this.apiUrl}/basket`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(basketItem)
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка при добавлении в корзину:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Обновить количество товара в корзине
|
||||
async updateBasketItem(productId, quantity) {
|
||||
try {
|
||||
const response = await fetch(`${this.apiUrl}/basket/${productId}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ quantity })
|
||||
});
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Ошибка при обновлении корзины:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Удалить товар из корзины
|
||||
async removeFromBasket(productId) {
|
||||
try {
|
||||
await fetch(`${this.apiUrl}/basket/${productId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Ошибка при удалении из корзины:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Очистить корзину
|
||||
async clearBasket() {
|
||||
try {
|
||||
const basketItems = await this.getBasketItems();
|
||||
for (const item of basketItems) {
|
||||
await this.removeFromBasket(item.id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка при очистке корзины:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Получить все товары из каталога
|
||||
async getProducts() {
|
||||
try {
|
||||
const response = await fetch(`${this.apiUrl}/shmots`);
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении товаров:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
113
components/basket/view.js
Normal file
@@ -0,0 +1,113 @@
|
||||
// view.js
|
||||
export class View {
|
||||
constructor() {
|
||||
this.basketContainer = document.getElementById('basketContainer');
|
||||
this.emptyBasketElement = document.querySelector('.empty-basket');
|
||||
}
|
||||
|
||||
// Показать корзину с товарами
|
||||
showBasket(items) {
|
||||
if (items.length === 0) {
|
||||
this.showEmptyBasket();
|
||||
return;
|
||||
}
|
||||
|
||||
this.hideEmptyBasket();
|
||||
|
||||
const basketHTML = items.map(item => this.createBasketItemHTML(item)).join('');
|
||||
this.basketContainer.innerHTML = `
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card border-0 shadow">
|
||||
<div class="card-header" style="background-color: #00264d; color: white;">
|
||||
<h5 class="mb-0"><i class="bi bi-cart me-2"></i>Корзина</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
${basketHTML}
|
||||
<div class="d-flex justify-content-between align-items-center mt-4 pt-3 border-top">
|
||||
<h5>Итого: $${this.calculateTotal(items).toFixed(2)}</h5>
|
||||
<button class="btn btn-lg" style="background-color: #00264d; color: white;" id="checkoutBtn">
|
||||
<i class="bi bi-credit-card me-2"></i>Оформить заказ
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Создать HTML для элемента корзины
|
||||
createBasketItemHTML(item) {
|
||||
return `
|
||||
<div class="row align-items-center mb-3 basket-item" data-id="${item.id}">
|
||||
<div class="col-md-2">
|
||||
<img src="${item.image}" alt="${item.name}" class="img-fluid rounded" style="max-height: 80px;">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6 class="mb-1">${item.name}</h6>
|
||||
<p class="text-muted small mb-0">${item.description}</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<span class="fw-bold">$${item.price}</span>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="input-group input-group-sm">
|
||||
<button class="btn btn-outline-secondary decrease-btn" type="button">-</button>
|
||||
<input type="number" class="form-control text-center quantity-input" value="${item.quantity}" min="1">
|
||||
<button class="btn btn-outline-secondary increase-btn" type="button">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<span class="fw-bold me-3">$${(item.price * item.quantity).toFixed(2)}</span>
|
||||
<button class="btn btn-sm btn-outline-danger remove-btn">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Показать пустую корзину
|
||||
showEmptyBasket() {
|
||||
if (this.emptyBasketElement) {
|
||||
this.emptyBasketElement.style.display = 'block';
|
||||
}
|
||||
if (this.basketContainer) {
|
||||
this.basketContainer.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Скрыть сообщение о пустой корзине
|
||||
hideEmptyBasket() {
|
||||
if (this.emptyBasketElement) {
|
||||
this.emptyBasketElement.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Рассчитать общую сумму
|
||||
calculateTotal(items) {
|
||||
return items.reduce((total, item) => total + (item.price * item.quantity), 0);
|
||||
}
|
||||
|
||||
// Показать уведомление
|
||||
showNotification(message, type = 'success') {
|
||||
// Создаем элемент уведомления
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `alert alert-${type === 'success' ? 'success' : 'danger'} alert-dismissible fade show`;
|
||||
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 1050; min-width: 300px;';
|
||||
notification.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Автоматически удаляем через 3 секунды
|
||||
setTimeout(() => {
|
||||
if (notification.parentNode) {
|
||||
notification.remove();
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
94
components/likes/controller.js
Normal file
@@ -0,0 +1,94 @@
|
||||
// components/likes/controller.js
|
||||
export class LikesController {
|
||||
constructor(model, view) {
|
||||
this.model = model;
|
||||
this.view = view;
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
if (window.location.pathname.includes('likes.html')) {
|
||||
await this.loadLikes();
|
||||
this.setupLikesEventListeners();
|
||||
}
|
||||
|
||||
if (window.location.pathname.includes('catalog.html')) {
|
||||
this.setupCatalogEventListeners();
|
||||
}
|
||||
}
|
||||
|
||||
async loadLikes() {
|
||||
const items = await this.model.getLikesItems();
|
||||
this.view.showLikes(items);
|
||||
}
|
||||
|
||||
setupLikesEventListeners() {
|
||||
document.addEventListener('click', async (e) => {
|
||||
const likeItem = e.target.closest('.like-item');
|
||||
if (!likeItem) return;
|
||||
|
||||
const productId = likeItem.dataset.id;
|
||||
|
||||
// удалить
|
||||
if (e.target.closest('.remove-like-btn')) {
|
||||
await this.model.removeFromLikes(productId);
|
||||
this.view.showNotification('Товар удален из избранного');
|
||||
await this.loadLikes();
|
||||
}
|
||||
|
||||
// перенести в корзину
|
||||
if (e.target.closest('.move-to-basket-btn')) {
|
||||
const items = await this.model.getLikesItems();
|
||||
const product = items.find(item => item.id === productId);
|
||||
if (product) {
|
||||
await this.model.moveToBasket(product);
|
||||
this.view.showNotification('Товар перенесен в корзину');
|
||||
await this.loadLikes();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setupCatalogEventListeners() {
|
||||
document.addEventListener('click', async (e) => {
|
||||
const card = e.target.closest('.card');
|
||||
if (!card) return;
|
||||
|
||||
if (e.target.closest('.like-btn')) {
|
||||
const product = this.extractProductData(card);
|
||||
if (product) {
|
||||
await this.model.addToLikes(product);
|
||||
this.view.showNotification('Товар добавлен в избранное!');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
extractProductData(card) {
|
||||
try {
|
||||
const name = card.querySelector('.card-title').textContent;
|
||||
const priceText = card.querySelector('.text-muted').textContent.replace('$', '');
|
||||
const description = card.querySelector('.card-text').textContent;
|
||||
const image = card.querySelector('img').src;
|
||||
|
||||
// ✅ Вытаскиваем category и condition
|
||||
const category = card.querySelector('.col-6:nth-child(1) p')?.textContent.trim() || '';
|
||||
const condition = card.querySelector('.col-6:nth-child(2) p')?.textContent.trim() || '';
|
||||
|
||||
const id = btoa(`${name}-${priceText}`).substring(0, 8);
|
||||
|
||||
return {
|
||||
id: id,
|
||||
name: name.trim(),
|
||||
price: parseFloat(priceText),
|
||||
description: description.trim(),
|
||||
image: image,
|
||||
category: category,
|
||||
condition: condition
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Ошибка при извлечении данных товара:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
69
components/likes/model.js
Normal file
@@ -0,0 +1,69 @@
|
||||
// components/likes/model.js
|
||||
export class LikesModel {
|
||||
constructor() {
|
||||
this.apiUrl = 'http://localhost:3000';
|
||||
}
|
||||
|
||||
async request(url, options = {}) {
|
||||
const response = await fetch(`${this.apiUrl}${url}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers
|
||||
}
|
||||
});
|
||||
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async getLikesItems() {
|
||||
try {
|
||||
return await this.request('/likes');
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении избранного:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async addToLikes(product) {
|
||||
try {
|
||||
const items = await this.getLikesItems();
|
||||
const exists = items.find(item => item.id === product.id);
|
||||
if (!exists) {
|
||||
const response = await fetch(`${this.apiUrl}/likes`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(product)
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка при добавлении в избранное:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async removeFromLikes(productId) {
|
||||
try {
|
||||
await fetch(`${this.apiUrl}/likes/${productId}`, { method: 'DELETE' });
|
||||
} catch (error) {
|
||||
console.error('Ошибка при удалении из избранного:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async moveToBasket(product) {
|
||||
try {
|
||||
// 1. Добавляем в корзину
|
||||
const basketRes = await fetch(`${this.apiUrl}/basket`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ...product, quantity: 1, addedAt: new Date().toISOString() })
|
||||
});
|
||||
await basketRes.json();
|
||||
|
||||
// 2. Удаляем из избранного
|
||||
await this.removeFromLikes(product.id);
|
||||
} catch (error) {
|
||||
console.error('Ошибка при переносе товара в корзину:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
99
components/likes/view.js
Normal file
@@ -0,0 +1,99 @@
|
||||
// components/likes/view.js
|
||||
export class LikesView {
|
||||
constructor() {
|
||||
this.likesContainer = document.getElementById('likesContainer');
|
||||
this.emptyLikesElement = document.querySelector('.empty-likes');
|
||||
}
|
||||
|
||||
showLikes(items) {
|
||||
if (!this.likesContainer) return;
|
||||
|
||||
if (!items || items.length === 0) {
|
||||
this.showEmptyLikes();
|
||||
return;
|
||||
}
|
||||
|
||||
// 👉 Если товары есть — убираем блок "пусто"
|
||||
this.hideEmptyLikes();
|
||||
|
||||
const likesHTML = items.map(item => this.createLikesItemHTML(item)).join('');
|
||||
|
||||
// 👉 Добавляем заголовок "Избранное"
|
||||
this.likesContainer.innerHTML = `
|
||||
<h2 class="mb-4 text-center">Избранное</h2>
|
||||
<div class="row g-3">${likesHTML}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
createLikesItemHTML(item) {
|
||||
return `
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 border-0 shadow like-item" data-id="${item.id}">
|
||||
<img src="${item.image}" class="card-img-top" alt="${item.name}">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">${item.name}</h5>
|
||||
<p class="card-text">${item.description}</p>
|
||||
|
||||
<!-- ✅ Добавляем Category и Condition -->
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h6 class="mb-1">Category:</h6>
|
||||
<p class="card-text">${item.category || '-'}</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h6 class="mb-1">Condition:</h6>
|
||||
<p class="card-text">${item.condition || '-'}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<!-- Цена слева -->
|
||||
<span class="fw-bold text-muted fs-3 price-large">$${item.price}</span>
|
||||
|
||||
<!-- Кнопки справа -->
|
||||
<div class="d-flex flex-column gap-1">
|
||||
<button class="btn btn-sm btn-outline-primary move-to-basket-btn">
|
||||
<i class="bi bi-cart-plus"></i> В корзину
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger remove-like-btn">
|
||||
<i class="bi bi-trash"></i> Удалить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
showEmptyLikes() {
|
||||
if (this.emptyLikesElement) {
|
||||
this.emptyLikesElement.style.display = 'block';
|
||||
}
|
||||
if (this.likesContainer) {
|
||||
this.likesContainer.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
hideEmptyLikes() {
|
||||
if (this.emptyLikesElement) {
|
||||
this.emptyLikesElement.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
showNotification(message, type = 'success') {
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `alert alert-${type === 'success' ? 'success' : 'danger'} alert-dismissible fade show`;
|
||||
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 1050; min-width: 300px;';
|
||||
notification.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
document.body.appendChild(notification);
|
||||
setTimeout(() => {
|
||||
if (notification.parentNode) notification.remove();
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
158
contacts.html
@@ -5,20 +5,87 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop contacts</title>
|
||||
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<!-- Кастомные стили -->
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #00264d;
|
||||
}
|
||||
main {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
footer {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.table-custom {
|
||||
background-color: #00264d;
|
||||
color: white;
|
||||
}
|
||||
.table-custom thead th {
|
||||
background-color: #001a3a;
|
||||
color: white;
|
||||
}
|
||||
.table-custom tbody tr:hover {
|
||||
background-color: #003366;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигация (как в main.html) -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<!-- ... та же навигация, что и в main.html ... -->
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="main.html">
|
||||
<img src="img/cyxaruk shop logo.jpg" alt="логотип" width="50" height="50" class="rounded-circle me-2">
|
||||
<span class="fw-bold">cyxaruk shop</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-list-ul me-1"></i>Каталог
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="contacts.html"><i class="bi bi-telephone me-1"></i>Контакты</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="likes.html"><i class="bi bi-heart me-1"></i>Избранное</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="basket.html"><i class="bi bi-cart me-1"></i>Корзина</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar .dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.navbar .dropdown .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<main class="container my-4">
|
||||
<h1 class="text-center mb-4">Контакты</h1>
|
||||
|
||||
@@ -28,9 +95,9 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<caption>Контакты (звонить только в поддержку)</caption>
|
||||
<thead class="table-dark">
|
||||
<table class="table table-custom table-striped table-hover">
|
||||
<caption class="text-dark">Контакты (звонить только в поддержку)</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ФИО</th>
|
||||
<th>Должность</th>
|
||||
@@ -45,50 +112,51 @@
|
||||
<td>89876320523</td>
|
||||
<td>@RBCScyxaruk</td>
|
||||
</tr>
|
||||
<!-- Остальные контакты аналогично -->
|
||||
<tr>
|
||||
<td>Ауц Евгений Валерьевич</td>
|
||||
<td>Продавец / поддержка круглосуточная</td>
|
||||
<td>89021263060</td>
|
||||
<td>@yevgenauts</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Данилюк Анжела</td>
|
||||
<td>Продавец / консультант</td>
|
||||
<td>89176235020</td>
|
||||
<td>@bomzhela</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Форма обратной связи -->
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header" style="background-color: #00264d; color: white;">
|
||||
<h5 class="mb-0"><i class="bi bi-envelope me-2"></i>Форма обратной связи</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="name" class="form-label">Ваше имя</label>
|
||||
<input type="text" class="form-control" id="name" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="form-control" id="email" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="message" class="form-label">Сообщение</label>
|
||||
<textarea class="form-control" id="message" rows="3" required></textarea>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-send me-2"></i>Отправить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Подвал (как в main.html) -->
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<!-- ... тот же подвал, что и в main.html ... -->
|
||||
<footer class="py-4" style="background-color: #00264d; color: white;">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<a href="https://t.me/cyxarukShop" class="text-white me-3">
|
||||
<i class="bi bi-telegram fs-2"></i>
|
||||
</a>
|
||||
<span>Подпишитесь на нас в Telegram</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="https://www.avito.ru/..." class="text-white me-3">
|
||||
<i class="bi bi-shop-window fs-2"></i>
|
||||
</a>
|
||||
<span>Мы на Авито</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<h5>Контакты</h5>
|
||||
<p><i class="bi bi-telephone me-2"></i>89876320523</p>
|
||||
<p><i class="bi bi-geo-alt me-2"></i>Ulyanovsk, Russia</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
75
db.json
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"shmots": [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "stone island",
|
||||
"price": 1999.99,
|
||||
"description": "super idol rovny pacan, groza rayona, mother's modnik, патч на месте",
|
||||
"image": "img/stonik.jpg",
|
||||
"category": "1",
|
||||
"condition": "1"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "adidas",
|
||||
"price": 19.99,
|
||||
"description": "sportik, street, baskemtball, air, old school",
|
||||
"image": "img/adidas.jpg",
|
||||
"category": "1",
|
||||
"condition": "2"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"name": "napapisaj",
|
||||
"price": 1499.99,
|
||||
"description": "super idol rovny pacan, groza rayona, mother's modnik, +rep from brothers",
|
||||
"image": "img/napapisaj.jpg",
|
||||
"category": "1",
|
||||
"condition": "2"
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"name": "samba",
|
||||
"price": 449.99,
|
||||
"description": "super idol rovny pacan, groza rayona, mother's modnik, +rep from brothers",
|
||||
"image": "img/samba.jpg",
|
||||
"category": "2",
|
||||
"condition": "1"
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"name": "lacoste",
|
||||
"price": 399.99,
|
||||
"description": "style, nice, mother's modnik, cotton, krokodil",
|
||||
"image": "img/lacoste.jpg",
|
||||
"category": "1",
|
||||
"condition": "1"
|
||||
}
|
||||
],
|
||||
"category": [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "men"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "women"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"name": "uni"
|
||||
}
|
||||
],
|
||||
"condition": [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "new"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "wu"
|
||||
}
|
||||
],
|
||||
"likes": [],
|
||||
"basket": []
|
||||
}
|
||||
BIN
dist/assets/adidas-gadQV-Lz.jpg
vendored
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
dist/assets/ava-DiHUHyvl.jpg
vendored
Normal file
|
After Width: | Height: | Size: 12 KiB |
49
dist/assets/controller-BHzoImTo.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
class r{constructor(){this.apiUrl="http://localhost:3000"}async request(t,s={}){try{const e=await fetch(`${this.apiUrl}${t}`,{...s,headers:{"Content-Type":"application/json",...s.headers}});if(!e.ok)throw new Error(`HTTP error! status: ${e.status}`);return await e.json()}catch(e){throw console.error("Request failed:",e),e}}async getBasketItems(){try{return await this.request("/basket")}catch(t){return console.error("Ошибка при получении корзины:",t),[]}}async addToBasket(t){try{const e=(await this.getBasketItems()).find(a=>a.id===t.id);if(e)await this.updateBasketItem(t.id,e.quantity+1);else{const a={...t,quantity:1,addedAt:new Date().toISOString()};return await(await fetch(`${this.apiUrl}/basket`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})).json()}}catch(s){console.error("Ошибка при добавлении в корзину:",s)}}async updateBasketItem(t,s){try{return await(await fetch(`${this.apiUrl}/basket/${t}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({quantity:s})})).json()}catch(e){console.error("Ошибка при обновлении корзины:",e)}}async removeFromBasket(t){try{await fetch(`${this.apiUrl}/basket/${t}`,{method:"DELETE"})}catch(s){console.error("Ошибка при удалении из корзины:",s)}}async clearBasket(){try{const t=await this.getBasketItems();for(const s of t)await this.removeFromBasket(s.id)}catch(t){console.error("Ошибка при очистке корзины:",t)}}async getProducts(){try{return await(await fetch(`${this.apiUrl}/shmots`)).json()}catch(t){return console.error("Ошибка при получении товаров:",t),[]}}}class c{constructor(){this.basketContainer=document.getElementById("basketContainer"),this.emptyBasketElement=document.querySelector(".empty-basket")}showBasket(t){if(t.length===0){this.showEmptyBasket();return}this.hideEmptyBasket();const s=t.map(e=>this.createBasketItemHTML(e)).join("");this.basketContainer.innerHTML=`
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card border-0 shadow">
|
||||
<div class="card-header" style="background-color: #00264d; color: white;">
|
||||
<h5 class="mb-0"><i class="bi bi-cart me-2"></i>Корзина</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
${s}
|
||||
<div class="d-flex justify-content-between align-items-center mt-4 pt-3 border-top">
|
||||
<h5>Итого: $${this.calculateTotal(t).toFixed(2)}</h5>
|
||||
<button class="btn btn-lg" style="background-color: #00264d; color: white;" id="checkoutBtn">
|
||||
<i class="bi bi-credit-card me-2"></i>Оформить заказ
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`}createBasketItemHTML(t){return`
|
||||
<div class="row align-items-center mb-3 basket-item" data-id="${t.id}">
|
||||
<div class="col-md-2">
|
||||
<img src="${t.image}" alt="${t.name}" class="img-fluid rounded" style="max-height: 80px;">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6 class="mb-1">${t.name}</h6>
|
||||
<p class="text-muted small mb-0">${t.description}</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<span class="fw-bold">$${t.price}</span>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="input-group input-group-sm">
|
||||
<button class="btn btn-outline-secondary decrease-btn" type="button">-</button>
|
||||
<input type="number" class="form-control text-center quantity-input" value="${t.quantity}" min="1">
|
||||
<button class="btn btn-outline-secondary increase-btn" type="button">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<span class="fw-bold me-3">$${(t.price*t.quantity).toFixed(2)}</span>
|
||||
<button class="btn btn-sm btn-outline-danger remove-btn">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`}showEmptyBasket(){this.emptyBasketElement&&(this.emptyBasketElement.style.display="block"),this.basketContainer&&(this.basketContainer.innerHTML="")}hideEmptyBasket(){this.emptyBasketElement&&(this.emptyBasketElement.style.display="none")}calculateTotal(t){return t.reduce((s,e)=>s+e.price*e.quantity,0)}showNotification(t,s="success"){const e=document.createElement("div");e.className=`alert alert-${s==="success"?"success":"danger"} alert-dismissible fade show`,e.style.cssText="position: fixed; top: 20px; right: 20px; z-index: 1050; min-width: 300px;",e.innerHTML=`
|
||||
${t}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`,document.body.appendChild(e),setTimeout(()=>{e.parentNode&&e.remove()},3e3)}}class l{constructor(t,s){this.model=t,this.view=s,this.init()}async init(){window.location.pathname.includes("basket.html")&&(await this.loadBasket(),this.setupBasketEventListeners()),window.location.pathname.includes("catalog.html")&&this.setupCatalogEventListeners()}async loadBasket(){const t=await this.model.getBasketItems();this.view.showBasket(t)}setupBasketEventListeners(){document.addEventListener("click",async t=>{const s=t.target.closest(".basket-item");if(!s)return;const e=s.dataset.id;if(t.target.closest(".remove-btn")&&(await this.model.removeFromBasket(e),this.view.showNotification("Товар удален из корзины"),await this.loadBasket()),t.target.closest(".increase-btn")){const a=s.querySelector(".quantity-input"),i=parseInt(a.value)+1;a.value=i,await this.model.updateBasketItem(e,i),await this.loadBasket()}if(t.target.closest(".decrease-btn")){const a=s.querySelector(".quantity-input");let i=parseInt(a.value)-1;i<1&&(i=1),a.value=i,await this.model.updateBasketItem(e,i),await this.loadBasket()}}),document.addEventListener("change",async t=>{if(t.target.classList.contains("quantity-input")){const e=t.target.closest(".basket-item").dataset.id,a=parseInt(t.target.value)||1;if(a<1){t.target.value=1;return}await this.model.updateBasketItem(e,a),await this.loadBasket()}}),document.addEventListener("click",async t=>{if(t.target.id==="checkoutBtn"){if((await this.model.getBasketItems()).length===0){this.view.showNotification("Корзина пуста","error");return}this.view.showNotification("Заказ оформлен! Спасибо за покупку!"),await this.model.clearBasket(),await this.loadBasket()}})}setupCatalogEventListeners(){document.addEventListener("click",async t=>{if(t.target.closest(".btn")&&t.target.closest(".btn").textContent.includes("В корзину")){const s=t.target.closest(".card"),e=this.extractProductData(s);e&&(await this.model.addToBasket(e),this.view.showNotification("Товар добавлен в корзину!"))}})}extractProductData(t){try{const s=t.querySelector(".card-title").textContent,e=t.querySelector(".text-muted").textContent.replace("$",""),a=t.querySelector(".card-text").textContent,i=t.querySelector("img").src;return{id:btoa(`${s}-${e}`).substring(0,8),name:s.trim(),price:parseFloat(e),description:a.trim(),image:i}}catch(s){return console.error("Ошибка при извлечении данных товара:",s),null}}}export{l as C,r as M,c as V};
|
||||
46
dist/assets/controller-BsNF2rMP.js
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
class h{constructor(){this.apiUrl="http://localhost:3000"}async request(t,e={}){const s=await fetch(`${this.apiUrl}${t}`,{...e,headers:{"Content-Type":"application/json",...e.headers}});if(!s.ok)throw new Error(`HTTP error! status: ${s.status}`);return await s.json()}async getLikesItems(){try{return await this.request("/likes")}catch(t){return console.error("Ошибка при получении избранного:",t),[]}}async addToLikes(t){try{if(!(await this.getLikesItems()).find(i=>i.id===t.id))return await(await fetch(`${this.apiUrl}/likes`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}catch(e){console.error("Ошибка при добавлении в избранное:",e)}}async removeFromLikes(t){try{await fetch(`${this.apiUrl}/likes/${t}`,{method:"DELETE"})}catch(e){console.error("Ошибка при удалении из избранного:",e)}}async moveToBasket(t){try{await(await fetch(`${this.apiUrl}/basket`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...t,quantity:1,addedAt:new Date().toISOString()})})).json(),await this.removeFromLikes(t.id)}catch(e){console.error("Ошибка при переносе товара в корзину:",e)}}}class m{constructor(){this.likesContainer=document.getElementById("likesContainer"),this.emptyLikesElement=document.querySelector(".empty-likes")}showLikes(t){if(!this.likesContainer)return;if(!t||t.length===0){this.showEmptyLikes();return}this.hideEmptyLikes();const e=t.map(s=>this.createLikesItemHTML(s)).join("");this.likesContainer.innerHTML=`
|
||||
<h2 class="mb-4 text-center">Избранное</h2>
|
||||
<div class="row g-3">${e}</div>
|
||||
`}createLikesItemHTML(t){return`
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 border-0 shadow like-item" data-id="${t.id}">
|
||||
<img src="${t.image}" class="card-img-top" alt="${t.name}">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">${t.name}</h5>
|
||||
<p class="card-text">${t.description}</p>
|
||||
|
||||
<!-- ✅ Добавляем Category и Condition -->
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h6 class="mb-1">Category:</h6>
|
||||
<p class="card-text">${t.category||"-"}</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h6 class="mb-1">Condition:</h6>
|
||||
<p class="card-text">${t.condition||"-"}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<!-- Цена слева -->
|
||||
<span class="fw-bold text-muted fs-3 price-large">$${t.price}</span>
|
||||
|
||||
<!-- Кнопки справа -->
|
||||
<div class="d-flex flex-column gap-1">
|
||||
<button class="btn btn-sm btn-outline-primary move-to-basket-btn">
|
||||
<i class="bi bi-cart-plus"></i> В корзину
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger remove-like-btn">
|
||||
<i class="bi bi-trash"></i> Удалить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`}showEmptyLikes(){this.emptyLikesElement&&(this.emptyLikesElement.style.display="block"),this.likesContainer&&(this.likesContainer.innerHTML="")}hideEmptyLikes(){this.emptyLikesElement&&(this.emptyLikesElement.style.display="none")}showNotification(t,e="success"){const s=document.createElement("div");s.className=`alert alert-${e==="success"?"success":"danger"} alert-dismissible fade show`,s.style.cssText="position: fixed; top: 20px; right: 20px; z-index: 1050; min-width: 300px;",s.innerHTML=`
|
||||
${t}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`,document.body.appendChild(s),setTimeout(()=>{s.parentNode&&s.remove()},3e3)}}class p{constructor(t,e){this.model=t,this.view=e,this.init()}async init(){window.location.pathname.includes("likes.html")&&(await this.loadLikes(),this.setupLikesEventListeners()),window.location.pathname.includes("catalog.html")&&this.setupCatalogEventListeners()}async loadLikes(){const t=await this.model.getLikesItems();this.view.showLikes(t)}setupLikesEventListeners(){document.addEventListener("click",async t=>{const e=t.target.closest(".like-item");if(!e)return;const s=e.dataset.id;if(t.target.closest(".remove-like-btn")&&(await this.model.removeFromLikes(s),this.view.showNotification("Товар удален из избранного"),await this.loadLikes()),t.target.closest(".move-to-basket-btn")){const o=(await this.model.getLikesItems()).find(a=>a.id===s);o&&(await this.model.moveToBasket(o),this.view.showNotification("Товар перенесен в корзину"),await this.loadLikes())}})}setupCatalogEventListeners(){document.addEventListener("click",async t=>{const e=t.target.closest(".card");if(e&&t.target.closest(".like-btn")){const s=this.extractProductData(e);s&&(await this.model.addToLikes(s),this.view.showNotification("Товар добавлен в избранное!"))}})}extractProductData(t){var e,s;try{const i=t.querySelector(".card-title").textContent,o=t.querySelector(".text-muted").textContent.replace("$",""),a=t.querySelector(".card-text").textContent,r=t.querySelector("img").src,c=((e=t.querySelector(".col-6:nth-child(1) p"))==null?void 0:e.textContent.trim())||"",l=((s=t.querySelector(".col-6:nth-child(2) p"))==null?void 0:s.textContent.trim())||"";return{id:btoa(`${i}-${o}`).substring(0,8),name:i.trim(),price:parseFloat(o),description:a.trim(),image:r,category:c,condition:l}}catch(i){return console.error("Ошибка при извлечении данных товара:",i),null}}}export{m as L,p as a,h as b};
|
||||
BIN
dist/assets/lacoste-BSTUvTkt.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
1
dist/assets/modulepreload-polyfill-B5Qt9EMX.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))i(e);new MutationObserver(e=>{for(const r of e)if(r.type==="childList")for(const o of r.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&i(o)}).observe(document,{childList:!0,subtree:!0});function s(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),e.crossOrigin==="use-credentials"?r.credentials="include":e.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function i(e){if(e.ep)return;e.ep=!0;const r=s(e);fetch(e.href,r)}})();
|
||||
BIN
dist/assets/napapisaj-DNuXYAGR.jpg
vendored
Normal file
|
After Width: | Height: | Size: 260 KiB |
1
dist/assets/page2-Crmhwurg.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import"./modulepreload-polyfill-B5Qt9EMX.js";/* empty css */import{L as t,a as o,b as d}from"./controller-BsNF2rMP.js";import{V as i,C as s,M as r}from"./controller-BHzoImTo.js";document.addEventListener("DOMContentLoaded",function(){if(document.getElementById("productsContainer")){const e=new d,n=new t;new o(e,n)}});document.addEventListener("DOMContentLoaded",function(){if(document.getElementById("basketContainer")||document.getElementById("productsContainer")){const e=new r,n=new i;new s(e,n)}});
|
||||
1
dist/assets/page4-DyyBeFxE.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import"./modulepreload-polyfill-B5Qt9EMX.js";/* empty css */import{L as o,a as t,b as i}from"./controller-BsNF2rMP.js";document.addEventListener("DOMContentLoaded",function(){if(document.getElementById("likesContainer")){const e=new i,n=new o;new t(e,n)}});
|
||||
1
dist/assets/page5-SW2YIOd4.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import"./modulepreload-polyfill-B5Qt9EMX.js";/* empty css */import{V as n,C as o,M as d}from"./controller-BHzoImTo.js";document.addEventListener("DOMContentLoaded",function(){if(document.getElementById("basketContainer")||document.getElementById("productsContainer")){const e=new d,t=new n;new o(e,t)}});
|
||||
BIN
dist/assets/samba-C8wu5LAG.png
vendored
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
1
dist/assets/styles-DJDadfij.css
vendored
@@ -1 +0,0 @@
|
||||
body{padding-top:56px;background-color:#f8f9fa}.bg-custom{background-color:#00264d!important}.btn-custom{background-color:#00264d;border-color:#00264d;color:#fff}.btn-custom:hover{background-color:#036;border-color:#036;color:#fff}.card{transition:transform .3s ease}.card:hover{transform:translateY(-5px);box-shadow:0 10px 20px #0000001a}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.navbar-brand img{border:2px solid rgba(255,255,255,.1)}.form-control:focus{border-color:#00264d;box-shadow:0 0 0 .25rem #00264d40}@media (max-width: 768px){.navbar-brand span{font-size:1rem}.display-4{font-size:2rem}}
|
||||
1
dist/assets/styles-cpwRBDRQ.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
body{background-color:#f8f9fa;color:#00264d}.bg-custom{background-color:#00264d!important}.btn-custom{background-color:#00264d;border-color:#00264d;color:#fff}.btn-custom:hover{background-color:#036;border-color:#036;color:#fff}.card{transition:transform .3s ease}.card:hover{transform:translateY(-5px);box-shadow:0 10px 20px #0000001a}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.navbar-brand img{border:2px solid rgba(255,255,255,.1)}.form-control:focus{border-color:#00264d;box-shadow:0 0 0 .25rem #00264d40}@media (max-width: 768px){.navbar-brand span{font-size:1rem}.display-4{font-size:2rem}}
|
||||
111
dist/basket.html
vendored
@@ -5,22 +5,80 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop basket</title>
|
||||
<link rel="shortcut icon" href="/assets/favicon-cXvr3Sfo.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<!-- Кастомные стили -->
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
|
||||
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar .dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.navbar .dropdown .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* прижимаем футер вниз */
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1; /* растягивается, чтобы футер был внизу */
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/page5-SW2YIOd4.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/modulepreload-polyfill-B5Qt9EMX.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/controller-BHzoImTo.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/styles-cpwRBDRQ.css">
|
||||
</head>
|
||||
<body>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="main.html">
|
||||
<img src="/assets/cyxaruk%20shop%20logo-DRloma41.jpg" alt="логотип" width="50" height="50" class="rounded-circle me-2">
|
||||
<span class="fw-bold">cyxaruk shop</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-list-ul me-1"></i>Каталог
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="contacts.html"><i class="bi bi-telephone me-1"></i>Контакты</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="likes.html"><i class="bi bi-heart me-1"></i>Избранное</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="basket.html"><i class="bi bi-cart me-1"></i>Корзина</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</nav>
|
||||
|
||||
<main class="container my-4">
|
||||
<main class="container my-4">
|
||||
<div class="empty-basket text-center py-5">
|
||||
<h1 class="mb-4">Здесь будут лежать твои товары</h1>
|
||||
<p class="lead mb-4">А пока здесь так пусто...</p>
|
||||
@@ -30,14 +88,37 @@
|
||||
<i class="bi bi-arrow-left me-2"></i>Вернуться в каталог
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="basketContainer"></div>
|
||||
</main>
|
||||
|
||||
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<a href="https://t.me/cyxarukShop" class="text-white me-3">
|
||||
<i class="bi bi-telegram fs-2"></i>
|
||||
</a>
|
||||
<span>Подпишитесь на нас в Telegram</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="https://www.avito.ru/..." class="text-white me-3">
|
||||
<i class="bi bi-shop-window fs-2"></i>
|
||||
</a>
|
||||
<span>Мы на Авито</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<h5>Контакты</h5>
|
||||
<p><i class="bi bi-telephone me-2"></i>89876320523</p>
|
||||
<p><i class="bi bi-geo-alt me-2"></i>Ulyanovsk, Russia</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
403
dist/catalog.html
vendored
@@ -5,64 +5,162 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop catalog</title>
|
||||
<link rel="shortcut icon" href="/assets/favicon-cXvr3Sfo.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<!-- Кастомные стили -->
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
|
||||
<style>
|
||||
.like-btn.liked {
|
||||
color: #000000 !important;
|
||||
border-color: #dc3545 !important;
|
||||
}
|
||||
.like-btn.liked i {
|
||||
color: #dc3545 !important;
|
||||
}
|
||||
/* Черная оконтовка при наведении на нажатую кнопку */
|
||||
.like-btn.liked:hover i {
|
||||
text-shadow: 0 0 2px #000000,
|
||||
0 0 2px #000000,
|
||||
0 0 2px #000000;
|
||||
}
|
||||
/* Плавное изменение */
|
||||
.like-btn i {
|
||||
transition: text-shadow 0.2s ease;
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/page2-Crmhwurg.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/modulepreload-polyfill-B5Qt9EMX.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/controller-BsNF2rMP.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/controller-BHzoImTo.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/styles-cpwRBDRQ.css">
|
||||
</head>
|
||||
<body>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="main.html">
|
||||
<img src="/assets/cyxaruk%20shop%20logo-DRloma41.jpg" alt="логотип" width="50" height="50" class="rounded-circle me-2">
|
||||
<span class="fw-bold">cyxaruk shop</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-list-ul me-1"></i>Каталог
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="contacts.html"><i class="bi bi-telephone me-1"></i>Контакты</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="likes.html"><i class="bi bi-heart me-1"></i>Избранное</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="basket.html"><i class="bi bi-cart me-1"></i>Корзина</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar .dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.navbar .dropdown .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<main class="container my-4">
|
||||
<h1 class="text-center mb-4">Каталог товаров</h1>
|
||||
|
||||
<!-- Форма добавления товара -->
|
||||
<div class="card mb-4 border-0 shadow-sm">
|
||||
<div class="card-header" style="background-color: #00264d; color: white;">
|
||||
<h5 class="mb-0"><i class="bi bi-plus-circle me-2"></i>Добавить новый товар</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="addProductForm" class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="productName" class="form-label">Название товара</label>
|
||||
<main class="container my-4">
|
||||
<div class="accordion" id="accordionExample">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingOne">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" style="background-color: #b0d8ff;" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
Добавить товар
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body">
|
||||
<div class="card mb-4 border-0 shadow">
|
||||
<div class="card-body">
|
||||
<form id="addProductForm" class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="productName" class="form-label">Название товара</label>
|
||||
<input type="text" class="form-control" id="productName" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="productPrice" class="form-label">Цена</label>
|
||||
<input type="text" class="form-control" id="productPrice" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="productCategory" class="form-label">Категория</label>
|
||||
<select class="form-select" id="productCategory" required>
|
||||
<option value="">Выберите категорию</option>
|
||||
<option value="1">Для мужчин</option>
|
||||
<option value="2">Для женщин</option>
|
||||
<option value="3">Унисекс</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="productCondition" class="form-label">Состояние</label>
|
||||
<select class="form-select" id="productCondition" required>
|
||||
<option value="">Выберите состояние</option>
|
||||
<option value="1">Новый</option>
|
||||
<option value="2">Б/У</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="productDescription" class="form-label">Описание</label>
|
||||
<textarea class="form-control" id="productDescription" rows="3" required></textarea>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="productImage" class="form-label">Ссылка на изображение</label>
|
||||
<input type="text" class="form-control" id="productImage" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-check-circle me-2"></i>Добавить товар
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="productPrice" class="form-label">Цена</label>
|
||||
<input type="text" class="form-control" id="productPrice" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="productDescription" class="form-label">Описание</label>
|
||||
<textarea class="form-control" id="productDescription" rows="3" required></textarea>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="productImage" class="form-label">Ссылка на изображение</label>
|
||||
<input type="text" class="form-control" id="productImage" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-check-circle me-2"></i>Добавить товар
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 class="text-center mb-4 mt-2">Каталог товаров</h1>
|
||||
<!-- Карточки товаров -->
|
||||
<!-- Карточки товаров -->
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-5" id="productsContainer">
|
||||
<!-- Карточка товара 1 -->
|
||||
<div class="col">
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="/assets/stonik-D_cwcHTM.jpg" class="card-img-top" alt="Stone Island">
|
||||
<div class="card-body">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">Stone Island</h4>
|
||||
<p class="card-text">super idol rovny pacan, groza rayona, mother's modnik, патч на месте</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">men</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">new</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
@@ -72,7 +170,7 @@
|
||||
<i class="bi bi-cart-plus me-1"></i>В корзину
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
@@ -83,35 +181,219 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Карточка товара 2 -->
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="/assets/adidas-gadQV-Lz.jpg" class="card-img-top" alt="Adidas">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Adidas</h5>
|
||||
<p class="card-text">sportik, street, baskemtball, air, old school</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">men</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">wu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted">$19.99</span>
|
||||
<button class="btn btn-sm" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-cart-plus me-1"></i>В корзину
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-share"></i> Поделиться
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Карточка товара 3 -->
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="/assets/napapisaj-DNuXYAGR.jpg" class="card-img-top" alt="Napapisaj">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Napapisaj</h5>
|
||||
<p class="card-text">super idol rovny pacan, groza rayona, mother's modnik, +rep from brothers</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">men</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">wu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted">$1499.99</span>
|
||||
<button class="btn btn-sm" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-cart-plus me-1"></i>В корзину
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-share"></i> Поделиться
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Карточка товара 4 -->
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="/assets/lacoste-BSTUvTkt.png" class="card-img-top" alt="Lacoste">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Lacoste</h5>
|
||||
<p class="card-text">style, nice, mother's modnik, cotton, krokodil</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">uni</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">wu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted">$399.99</span>
|
||||
<button class="btn btn-sm" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-cart-plus me-1"></i>В корзину
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-share"></i> Поделиться
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Карточка товара 5 -->
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="/assets/samba-C8wu5LAG.png" class="card-img-top" alt="Samba">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Samba</h5>
|
||||
<p class="card-text">super idol rovny pacan, groza rayona, mother's modnik, +rep from brothers</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">women</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">new</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted">$449.99</span>
|
||||
<button class="btn btn-sm" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-cart-plus me-1"></i>В корзину
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-share"></i> Поделиться
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<a href="https://t.me/cyxarukShop" class="text-white me-3">
|
||||
<i class="bi bi-telegram fs-2"></i>
|
||||
</a>
|
||||
<span>Подпишитесь на нас в Telegram</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="https://www.avito.ru/..." class="text-white me-3">
|
||||
<i class="bi bi-shop-window fs-2"></i>
|
||||
</a>
|
||||
<span>Мы на Авито</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<h5>Контакты</h5>
|
||||
<p><i class="bi bi-telephone me-2"></i>89876320523</p>
|
||||
<p><i class="bi bi-geo-alt me-2"></i>Ulyanovsk, Russia</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
<script>
|
||||
document.getElementById("addProductForm").addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const name = document.getElementById('productName').value;
|
||||
const price = document.getElementById('productPrice').value;
|
||||
const description = document.getElementById('productDescription').value;
|
||||
const image = document.getElementById('productImage').value;
|
||||
e.preventDefault();
|
||||
const name = document.getElementById("productName").value;
|
||||
const price = document.getElementById("productPrice").value;
|
||||
const category = document.getElementById("productCategory").value;
|
||||
const condition = document.getElementById("productCondition").value;
|
||||
const description = document.getElementById("productDescription").value;
|
||||
const image = document.getElementById("productImage").value;
|
||||
|
||||
// Получаем текстовые значения для отображения
|
||||
const categoryText = document.getElementById("productCategory").options[document.getElementById("productCategory").selectedIndex].text;
|
||||
const conditionText = document.getElementById("productCondition").options[document.getElementById("productCondition").selectedIndex].text;
|
||||
|
||||
const productCard = `
|
||||
<div class="col">
|
||||
<div class="col">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<img src="${image}" class="card-img-top" alt="${name}">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">${name}</h5>
|
||||
<p class="card-text">${description}</p>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Category:</h5>
|
||||
<p class="card-text">${categoryText}</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 class="card-text mb-1">Condition:</h5>
|
||||
<p class="card-text">${conditionText}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
@@ -121,7 +403,7 @@
|
||||
<i class="bi bi-cart-plus me-1"></i>В корзину
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<div class="mt-2 d-flex justify-content-between">
|
||||
<button class="btn btn-sm btn-outline-secondary like-btn">
|
||||
<i class="bi bi-heart"></i> В избранное
|
||||
</button>
|
||||
@@ -132,10 +414,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
`;
|
||||
|
||||
document.getElementById("productsContainer").insertAdjacentHTML("beforeend", productCard);
|
||||
this.reset();
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
|
||||
|
||||
|
||||
254
dist/contacts.html
vendored
@@ -1,94 +1,162 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop contacts</title>
|
||||
<link rel="shortcut icon" href="/assets/favicon-cXvr3Sfo.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<!-- Кастомные стили -->
|
||||
|
||||
<link rel="stylesheet" crossorigin href="/assets/styles-DJDadfij.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигация (как в main.html) -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<!-- ... та же навигация, что и в main.html ... -->
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<main class="container my-4">
|
||||
<h1 class="text-center mb-4">Контакты</h1>
|
||||
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-header" style="background-color: #00264d; color: white;">
|
||||
<h5 class="mb-0"><i class="bi bi-info-circle me-2"></i>Контактная информация</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<caption>Контакты (звонить только в поддержку)</caption>
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>ФИО</th>
|
||||
<th>Должность</th>
|
||||
<th>Телефон</th>
|
||||
<th>Телеграм</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Платонов Артемий Михайлович</td>
|
||||
<td>Администрация / продавец</td>
|
||||
<td>89876320523</td>
|
||||
<td>@RBCScyxaruk</td>
|
||||
</tr>
|
||||
<!-- Остальные контакты аналогично -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Форма обратной связи -->
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header" style="background-color: #00264d; color: white;">
|
||||
<h5 class="mb-0"><i class="bi bi-envelope me-2"></i>Форма обратной связи</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="name" class="form-label">Ваше имя</label>
|
||||
<input type="text" class="form-control" id="name" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="form-control" id="email" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="message" class="form-label">Сообщение</label>
|
||||
<textarea class="form-control" id="message" rows="3" required></textarea>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-send me-2"></i>Отправить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Подвал (как в main.html) -->
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<!-- ... тот же подвал, что и в main.html ... -->
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop contacts</title>
|
||||
<link rel="shortcut icon" href="/assets/favicon-cXvr3Sfo.ico" type="image/x-icon">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #00264d;
|
||||
}
|
||||
main {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
footer {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.table-custom {
|
||||
background-color: #00264d;
|
||||
color: white;
|
||||
}
|
||||
.table-custom thead th {
|
||||
background-color: #001a3a;
|
||||
color: white;
|
||||
}
|
||||
.table-custom tbody tr:hover {
|
||||
background-color: #003366;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="main.html">
|
||||
<img src="/assets/cyxaruk%20shop%20logo-DRloma41.jpg" alt="логотип" width="50" height="50" class="rounded-circle me-2">
|
||||
<span class="fw-bold">cyxaruk shop</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-list-ul me-1"></i>Каталог
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="contacts.html"><i class="bi bi-telephone me-1"></i>Контакты</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="likes.html"><i class="bi bi-heart me-1"></i>Избранное</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="basket.html"><i class="bi bi-cart me-1"></i>Корзина</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar .dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.navbar .dropdown .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<main class="container my-4">
|
||||
<h1 class="text-center mb-4">Контакты</h1>
|
||||
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-header" style="background-color: #00264d; color: white;">
|
||||
<h5 class="mb-0"><i class="bi bi-info-circle me-2"></i>Контактная информация</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-custom table-striped table-hover">
|
||||
<caption class="text-dark">Контакты (звонить только в поддержку)</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ФИО</th>
|
||||
<th>Должность</th>
|
||||
<th>Телефон</th>
|
||||
<th>Телеграм</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Платонов Артемий Михайлович</td>
|
||||
<td>Администрация / продавец</td>
|
||||
<td>89876320523</td>
|
||||
<td>@RBCScyxaruk</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ауц Евгений Валерьевич</td>
|
||||
<td>Продавец / поддержка круглосуточная</td>
|
||||
<td>89021263060</td>
|
||||
<td>@yevgenauts</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Данилюк Анжела</td>
|
||||
<td>Продавец / консультант</td>
|
||||
<td>89176235020</td>
|
||||
<td>@bomzhela</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="py-4" style="background-color: #00264d; color: white;">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<a href="https://t.me/cyxarukShop" class="text-white me-3">
|
||||
<i class="bi bi-telegram fs-2"></i>
|
||||
</a>
|
||||
<span>Подпишитесь на нас в Telegram</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="https://www.avito.ru/..." class="text-white me-3">
|
||||
<i class="bi bi-shop-window fs-2"></i>
|
||||
</a>
|
||||
<span>Мы на Авито</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<h5>Контакты</h5>
|
||||
<p><i class="bi bi-telephone me-2"></i>89876320523</p>
|
||||
<p><i class="bi bi-geo-alt me-2"></i>Ulyanovsk, Russia</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
97
dist/likes.html
vendored
@@ -3,41 +3,106 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop likes</title>
|
||||
<title>cyxaruk shop basket</title>
|
||||
<link rel="shortcut icon" href="/assets/favicon-cXvr3Sfo.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<!-- Кастомные стили -->
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
|
||||
<script type="module" crossorigin src="/assets/page4-DyyBeFxE.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/modulepreload-polyfill-B5Qt9EMX.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/controller-BsNF2rMP.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/styles-cpwRBDRQ.css">
|
||||
</head>
|
||||
<body>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="main.html">
|
||||
<img src="/assets/cyxaruk%20shop%20logo-DRloma41.jpg" alt="логотип" width="50" height="50" class="rounded-circle me-2">
|
||||
<span class="fw-bold">cyxaruk shop</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-list-ul me-1"></i>Каталог
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="contacts.html"><i class="bi bi-telephone me-1"></i>Контакты</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="likes.html"><i class="bi bi-heart me-1"></i>Избранное</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="basket.html"><i class="bi bi-cart me-1"></i>Корзина</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar .dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.navbar .dropdown .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<main class="container my-4">
|
||||
<main class="container my-4">
|
||||
<div class="text-center py-5 empty-likes">
|
||||
<h1 class="mb-4">Здесь будут лежать товары, которые тебе понравились</h1>
|
||||
<p class="lead mb-4">А пока здесь так пусто...</p>
|
||||
<p class="lead mb-4">А пока здесь так пусто...</p>
|
||||
<img src="/assets/sad2-GwJVM7cz.jpeg" alt="Пусто" class="img-fluid rounded" style="max-height: 300px;">
|
||||
<div class="mt-4">
|
||||
<a href="catalog.html" class="btn btn-lg" style="background-color: #00264d; color: white;">
|
||||
<a href="catalog.html" class="btn btn-lg" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-arrow-left me-2"></i>Вернуться в каталог
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="likesContainer"></div>
|
||||
</main>
|
||||
|
||||
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<a href="https://t.me/cyxarukShop" class="text-white me-3">
|
||||
<i class="bi bi-telegram fs-2"></i>
|
||||
</a>
|
||||
<span>Подпишитесь на нас в Telegram</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="https://www.avito.ru/..." class="text-white me-3">
|
||||
<i class="bi bi-shop-window fs-2"></i>
|
||||
</a>
|
||||
<span>Мы на Авито</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<h5>Контакты</h5>
|
||||
<p><i class="bi bi-telephone me-2"></i>89876320523</p>
|
||||
<p><i class="bi bi-geo-alt me-2"></i>Ulyanovsk, Russia</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
|
||||
94
dist/main.html
vendored
@@ -5,15 +5,16 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop</title>
|
||||
<link rel="shortcut icon" href="/assets/favicon-cXvr3Sfo.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<!-- Кастомные стили -->
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
|
||||
<style>
|
||||
body {
|
||||
color: #00264d;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" crossorigin href="/assets/styles-cpwRBDRQ.css">
|
||||
</head>
|
||||
<body>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<div class="container">
|
||||
@@ -26,15 +27,15 @@
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-list-ul me-1"></i>Каталог
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -51,14 +52,23 @@
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar .dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.navbar .dropdown .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<main class="container my-4">
|
||||
<main class="container my-4">
|
||||
<div class="row align-items-center mb-5">
|
||||
<div class="col-md-6 mb-4 mb-md-0">
|
||||
<img src="/assets/%D1%88%D0%BC%D0%BE%D1%82%D0%BA%D0%B82-CnCqIiH2.jpg" alt="Промо" class="img-fluid rounded shadow">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 text-center text-md-end d-flex flex-column align-items-md-center">
|
||||
<h2 class="fw-bold mb-3"><em>Official cyxaruk shop website</em></h2>
|
||||
<a href="catalog.html" class="btn btn-lg" style="background-color: #00264d; color: white;">
|
||||
@@ -66,12 +76,10 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-center mb-5">
|
||||
<h1 class="fw-bold">ONLY THE FATTEST STUFF</h1>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row g-4 mb-5">
|
||||
<div class="col-md-6">
|
||||
@@ -81,23 +89,60 @@
|
||||
<img src="/assets/%D1%88%D0%BC%D0%BE%D1%82%D0%BA%D0%B831-TxMfC034.jpg" alt="Товары 2" class="img-fluid rounded shadow">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h2 class="text-center mb-4"><em>Отзывы</em></h2>
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<div class="card-body text-center">
|
||||
<div class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; background-color: #e9ecef;"></div>
|
||||
<h5 class="card-title">Pistoletov Sasha</h5>
|
||||
<div class="card-body text-center">
|
||||
<img src="/assets/ava-DiHUHyvl.jpg" class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; object-fit: cover;" alt="AUC EVGEN">
|
||||
<h5 class="card-title">AUC EVGEN</h5>
|
||||
<p class="card-text">Сотрудничаем уже 7 лет, все четко</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<div class="card-body text-center">
|
||||
<img src="/assets/ava-DiHUHyvl.jpg" class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; object-fit: cover;" alt="Vupava Kitalya">
|
||||
<h5 class="card-title">Vupava Kitalya</h5>
|
||||
<p class="card-text">Просил найти его бренд Napapisaj, очень редкая штука, но он справился, 10/10</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<div class="card-body text-center">
|
||||
<img src="/assets/ava-DiHUHyvl.jpg" class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; object-fit: cover;" alt="Hater228">
|
||||
<h5 class="card-title">Hater228</h5>
|
||||
<p class="card-text">Как от ****** отойдешь, цену поменяй, клоун</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<div class="card-body text-center">
|
||||
<img src="/assets/ava-DiHUHyvl.jpg" class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; object-fit: cover;" alt="Anjela Danil">
|
||||
<h5 class="card-title">Anjela Danil</h5>
|
||||
<p class="card-text">Норм продавец, 9/10, пук пук</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<div class="card-body text-center">
|
||||
<img src="/assets/ava-DiHUHyvl.jpg" class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; object-fit: cover;" alt="Bima Daryshev">
|
||||
<h5 class="card-title">Bima Daryshev</h5>
|
||||
<p class="card-text">При покупке не возникло никаких проблем, предоставляет огромное кол-во скидок</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<div class="container">
|
||||
@@ -124,7 +169,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
BIN
img/ava.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 259 KiB |
105
likes.html
@@ -3,41 +3,116 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop likes</title>
|
||||
<title>cyxaruk shop basket</title>
|
||||
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<!-- Кастомные стили -->
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигация (как в main.html) -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<!-- ... та же навигация, что и в main.html ... -->
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="main.html">
|
||||
<img src="img/cyxaruk shop logo.jpg" alt="логотип" width="50" height="50" class="rounded-circle me-2">
|
||||
<span class="fw-bold">cyxaruk shop</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-list-ul me-1"></i>Каталог
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="contacts.html"><i class="bi bi-telephone me-1"></i>Контакты</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="likes.html"><i class="bi bi-heart me-1"></i>Избранное</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="basket.html"><i class="bi bi-cart me-1"></i>Корзина</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar .dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.navbar .dropdown .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<main class="container my-4">
|
||||
<div class="text-center py-5">
|
||||
<div class="text-center py-5 empty-likes">
|
||||
<h1 class="mb-4">Здесь будут лежать товары, которые тебе понравились</h1>
|
||||
<p class="lead mb-4">А пока здесь так пусто...</p>
|
||||
<img src="img/sad2.jpeg" alt="Пустое избранное" class="img-fluid rounded" style="max-height: 300px;">
|
||||
<img src="img/sad2.jpeg" alt="Пусто" class="img-fluid rounded" style="max-height: 300px;">
|
||||
<div class="mt-4">
|
||||
<a href="catalog.html" class="btn btn-lg" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-heart me-2"></i>Найти что-то интересное
|
||||
<i class="bi bi-arrow-left me-2"></i>Вернуться в каталог
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="likesContainer"></div>
|
||||
</main>
|
||||
|
||||
<!-- Подвал (как в main.html) -->
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<!-- ... тот же подвал, что и в main.html ... -->
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<a href="https://t.me/cyxarukShop" class="text-white me-3">
|
||||
<i class="bi bi-telegram fs-2"></i>
|
||||
</a>
|
||||
<span>Подпишитесь на нас в Telegram</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="https://www.avito.ru/..." class="text-white me-3">
|
||||
<i class="bi bi-shop-window fs-2"></i>
|
||||
</a>
|
||||
<span>Мы на Авито</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<h5>Контакты</h5>
|
||||
<p><i class="bi bi-telephone me-2"></i>89876320523</p>
|
||||
<p><i class="bi bi-geo-alt me-2"></i>Ulyanovsk, Russia</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<script type="module">
|
||||
import { LikesModel } from '/components/likes/model.js';
|
||||
import { LikesView } from '/components/likes/view.js';
|
||||
import { LikesController } from '/components/likes/controller.js';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (document.getElementById('likesContainer')) {
|
||||
const model = new LikesModel();
|
||||
const view = new LikesView();
|
||||
new LikesController(model, view);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
92
main.html
@@ -5,15 +5,16 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>cyxaruk shop</title>
|
||||
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<!-- Кастомные стили -->
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
<style>
|
||||
body {
|
||||
color: #00264d;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Навигация -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="main.html">
|
||||
@@ -26,15 +27,15 @@
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button" data-bs-toggle="dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="catalog.html" id="navbarDropdown" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-list-ul me-1"></i>Каталог
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-emoji-smile me-2"></i>Для детей</a></li>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-male me-2"></i>Для мужчин</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-gender-female me-2"></i>Для женщин</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
<li><a class="dropdown-item" href="catalog.html"><i class="bi bi-globe me-2"></i>Заказ из-за границы</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
@@ -51,14 +52,23 @@
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar .dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.navbar .dropdown .dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<main class="container my-4">
|
||||
<!-- Промо-секция -->
|
||||
<div class="row align-items-center mb-5">
|
||||
<div class="col-md-6 mb-4 mb-md-0">
|
||||
<img src="img/шмотки2.jpg" alt="Промо" class="img-fluid rounded shadow">
|
||||
</div>
|
||||
<div class="col-md-6 text-center text-md-start">
|
||||
<div class="col-md-6 text-center text-md-end d-flex flex-column align-items-md-center">
|
||||
<h2 class="fw-bold mb-3"><em>Official cyxaruk shop website</em></h2>
|
||||
<a href="catalog.html" class="btn btn-lg" style="background-color: #00264d; color: white;">
|
||||
<i class="bi bi-bag me-2"></i>Начать покупки
|
||||
@@ -66,12 +76,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Заголовок -->
|
||||
<div class="text-center mb-5">
|
||||
<h1 class="fw-bold">ONLY THE FATTEST STUFF</h1>
|
||||
</div>
|
||||
|
||||
<!-- Галерея -->
|
||||
<div class="row g-4 mb-5">
|
||||
<div class="col-md-6">
|
||||
<img src="img/шмотки.jpg" alt="Товары 1" class="img-fluid rounded shadow">
|
||||
@@ -81,23 +89,60 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Отзывы -->
|
||||
<h2 class="text-center mb-4"><em>Отзывы</em></h2>
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<div class="card-body text-center">
|
||||
<div class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; background-color: #e9ecef;"></div>
|
||||
<h5 class="card-title">Pistoletov Sasha</h5>
|
||||
<p class="card-text">стон 1200 рублей и расход, го можно пж?</p>
|
||||
<img src="img/ava.jpg" class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; object-fit: cover;" alt="AUC EVGEN">
|
||||
<h5 class="card-title">AUC EVGEN</h5>
|
||||
<p class="card-text">Сотрудничаем уже 7 лет, все четко</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<div class="card-body text-center">
|
||||
<img src="img/ava.jpg" class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; object-fit: cover;" alt="Vupava Kitalya">
|
||||
<h5 class="card-title">Vupava Kitalya</h5>
|
||||
<p class="card-text">Просил найти его бренд Napapisaj, очень редкая штука, но он справился, 10/10</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<div class="card-body text-center">
|
||||
<img src="img/ava.jpg" class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; object-fit: cover;" alt="Hater228">
|
||||
<h5 class="card-title">Hater228</h5>
|
||||
<p class="card-text">Как от ****** отойдешь, цену поменяй, клоун</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<div class="card-body text-center">
|
||||
<img src="img/ava.jpg" class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; object-fit: cover;" alt="Anjela Danil">
|
||||
<h5 class="card-title">Anjela Danil</h5>
|
||||
<p class="card-text">Норм продавец, 9/10, пук пук</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border-0 shadow">
|
||||
<div class="card-body text-center">
|
||||
<img src="img/ava.jpg" class="mx-auto mb-3 rounded-circle" style="width: 60px; height: 60px; object-fit: cover;" alt="Bima Daryshev">
|
||||
<h5 class="card-title">Bima Daryshev</h5>
|
||||
<p class="card-text">При покупке не возникло никаких проблем, предоставляет огромное кол-во скидок</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Остальные отзывы аналогично -->
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Подвал -->
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
@@ -124,7 +169,6 @@
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
16
node_modules/.bin/json-server
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../json-server/lib/bin.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../json-server/lib/bin.js" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/json-server.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\json-server\lib\bin.js" %*
|
||||
28
node_modules/.bin/json-server.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../json-server/lib/bin.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../json-server/lib/bin.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../json-server/lib/bin.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../json-server/lib/bin.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
634
node_modules/.package-lock.json
generated
vendored
@@ -173,6 +173,13 @@
|
||||
"url": "https://opencollective.com/unts"
|
||||
}
|
||||
},
|
||||
"node_modules/@polka/url": {
|
||||
"version": "1.0.0-next.29",
|
||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
|
||||
"integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
@@ -205,6 +212,327 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tinyhttp/accepts": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/accepts/-/accepts-2.2.3.tgz",
|
||||
"integrity": "sha512-9pQN6pJAJOU3McmdJWTcyq7LLFW8Lj5q+DadyKcvp+sxMkEpktKX5sbfJgJuOvjk6+1xWl7pe0YL1US1vaO/1w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime": "4.0.4",
|
||||
"negotiator": "^0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/tinyhttp/tinyhttp?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/accepts/node_modules/mime": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-4.0.4.tgz",
|
||||
"integrity": "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/app": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/app/-/app-2.5.2.tgz",
|
||||
"integrity": "sha512-DcB3Y8GQppLQlO2VxRYF7LzTEAoZb+VRQXuIsErcu2fNaM1xdx6NQZDso5rlZUiaeg6KYYRfU34N4XkZbv6jSA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tinyhttp/cookie": "2.1.1",
|
||||
"@tinyhttp/proxy-addr": "2.2.1",
|
||||
"@tinyhttp/req": "2.2.5",
|
||||
"@tinyhttp/res": "2.2.5",
|
||||
"@tinyhttp/router": "2.2.3",
|
||||
"header-range-parser": "1.1.3",
|
||||
"regexparam": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/tinyhttp/tinyhttp?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/content-disposition": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/content-disposition/-/content-disposition-2.2.2.tgz",
|
||||
"integrity": "sha512-crXw1txzrS36huQOyQGYFvhTeLeG0Si1xu+/l6kXUVYpE0TjFjEZRqTbuadQLfKGZ0jaI+jJoRyqaWwxOSHW2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/tinyhttp/tinyhttp?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/content-type": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/content-type/-/content-type-0.1.4.tgz",
|
||||
"integrity": "sha512-dl6f3SHIJPYbhsW1oXdrqOmLSQF/Ctlv3JnNfXAE22kIP7FosqJHxkz/qj2gv465prG8ODKH5KEyhBkvwrueKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/cookie": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/cookie/-/cookie-2.1.1.tgz",
|
||||
"integrity": "sha512-h/kL9jY0e0Dvad+/QU3efKZww0aTvZJslaHj3JTPmIPC9Oan9+kYqmh3M6L5JUQRuTJYFK2nzgL2iJtH2S+6dA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/tinyhttp/tinyhttp?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/cookie-signature": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/cookie-signature/-/cookie-signature-2.1.1.tgz",
|
||||
"integrity": "sha512-VDsSMY5OJfQJIAtUgeQYhqMPSZptehFSfvEEtxr+4nldPA8IImlp3QVcOVuK985g4AFR4Hl1sCbWCXoqBnVWnw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/cors": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/cors/-/cors-2.0.1.tgz",
|
||||
"integrity": "sha512-qrmo6WJuaiCzKWagv2yA/kw6hIISfF/hOqPWwmI6w0o8apeTMmRN3DoCFvQ/wNVuWVdU5J4KU7OX8aaSOEq51A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tinyhttp/vary": "^0.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20 || 14.x || >=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/encode-url": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/encode-url/-/encode-url-2.1.1.tgz",
|
||||
"integrity": "sha512-AhY+JqdZ56qV77tzrBm0qThXORbsVjs/IOPgGCS7x/wWnsa/Bx30zDUU/jPAUcSzNOzt860x9fhdGpzdqbUeUw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/etag": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/etag/-/etag-2.1.2.tgz",
|
||||
"integrity": "sha512-j80fPKimGqdmMh6962y+BtQsnYPVCzZfJw0HXjyH70VaJBHLKGF+iYhcKqzI3yef6QBNa8DKIPsbEYpuwApXTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/forwarded": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/forwarded/-/forwarded-2.1.2.tgz",
|
||||
"integrity": "sha512-9H/eulJ68ElY/+zYpTpNhZ7vxGV+cnwaR6+oQSm7bVgZMyuQfgROW/qvZuhmgDTIxnGMXst+Ba4ij6w6Krcs3w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/logger": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/logger/-/logger-2.1.0.tgz",
|
||||
"integrity": "sha512-Ma1fJ9CwUbn9r61/4HW6+nflsVoslpOnCrfQ6UeZq7GGIgwLzofms3HoSVG7M+AyRMJpxlfcDdbH5oFVroDMKA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"colorette": "^2.0.20",
|
||||
"dayjs": "^1.11.13",
|
||||
"http-status-emojis": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18 || >=16.20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/proxy-addr": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/proxy-addr/-/proxy-addr-2.2.1.tgz",
|
||||
"integrity": "sha512-BicqMqVI91hHq2BQmnqJUh0FQUnx7DncwSGgu2ghlh+JZG2rHK2ZN/rXkfhrx1rrUw6hnd0L36O8GPMh01+dDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tinyhttp/forwarded": "2.1.2",
|
||||
"ipaddr.js": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/req": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/req/-/req-2.2.5.tgz",
|
||||
"integrity": "sha512-trfsXwtmsNjMcGKcLJ+45h912kLRqBQCQD06ams3Tq0kf4gHLxjHjoYOC1Z9yGjOn81XllRx8wqvnvr+Kbe3gw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tinyhttp/accepts": "2.2.3",
|
||||
"@tinyhttp/type-is": "2.2.4",
|
||||
"@tinyhttp/url": "2.1.1",
|
||||
"header-range-parser": "^1.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/res": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/res/-/res-2.2.5.tgz",
|
||||
"integrity": "sha512-yBsqjWygpuKAVz4moWlP4hqzwiDDqfrn2mA0wviJAcgvGiyOErtlQwXY7aj3aPiCpURvxvEFO//Gdy6yV+xEpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tinyhttp/content-disposition": "2.2.2",
|
||||
"@tinyhttp/cookie": "2.1.1",
|
||||
"@tinyhttp/cookie-signature": "2.1.1",
|
||||
"@tinyhttp/encode-url": "2.1.1",
|
||||
"@tinyhttp/req": "2.2.5",
|
||||
"@tinyhttp/send": "2.2.3",
|
||||
"@tinyhttp/vary": "^0.1.3",
|
||||
"es-escape-html": "^0.1.1",
|
||||
"mime": "4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/res/node_modules/mime": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-4.0.4.tgz",
|
||||
"integrity": "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/router": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/router/-/router-2.2.3.tgz",
|
||||
"integrity": "sha512-O0MQqWV3Vpg/uXsMYg19XsIgOhwjyhTYWh51Qng7bxqXixxx2PEvZWnFjP7c84K7kU/nUX41KpkEBTLnznk9/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/send": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/send/-/send-2.2.3.tgz",
|
||||
"integrity": "sha512-o4cVHHGQ8WjVBS8UT0EE/2WnjoybrfXikHwsRoNlG1pfrC/Sd01u1N4Te8cOd/9aNGLr4mGxWb5qTm2RRtEi7g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tinyhttp/content-type": "^0.1.4",
|
||||
"@tinyhttp/etag": "2.1.2",
|
||||
"mime": "4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/send/node_modules/mime": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-4.0.4.tgz",
|
||||
"integrity": "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/type-is": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/type-is/-/type-is-2.2.4.tgz",
|
||||
"integrity": "sha512-7F328NheridwjIfefBB2j1PEcKKABpADgv7aCJaE8x8EON77ZFrAkI3Rir7pGjopV7V9MBmW88xUQigBEX2rmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tinyhttp/content-type": "^0.1.4",
|
||||
"mime": "4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/type-is/node_modules/mime": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-4.0.4.tgz",
|
||||
"integrity": "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/url": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/url/-/url-2.1.1.tgz",
|
||||
"integrity": "sha512-POJeq2GQ5jI7Zrdmj22JqOijB5/GeX+LEX7DUdml1hUnGbJOTWDx7zf2b5cCERj7RoXL67zTgyzVblBJC+NJWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinyhttp/vary": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@tinyhttp/vary/-/vary-0.1.3.tgz",
|
||||
"integrity": "sha512-SoL83sQXAGiHN1jm2VwLUWQSQeDAAl1ywOm6T0b0Cg1CZhVsjoiZadmjhxF6FHCCY7OHHVaLnTgSMxTPIDLxMg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
|
||||
@@ -595,6 +923,22 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@@ -615,6 +959,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/colorette": {
|
||||
"version": "2.0.20",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
|
||||
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
@@ -708,6 +1059,13 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
|
||||
@@ -841,6 +1199,35 @@
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dot-prop": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-9.0.0.tgz",
|
||||
"integrity": "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"type-fest": "^4.18.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/dot-prop/node_modules/type-fest": {
|
||||
"version": "4.41.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
|
||||
"integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
|
||||
"dev": true,
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@@ -965,6 +1352,16 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-escape-html": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-escape-html/-/es-escape-html-0.1.1.tgz",
|
||||
"integrity": "sha512-yUx1o+8RsG7UlszmYPtks+dm6Lho2m8lgHMOsLJQsFI0R8XwUJwiMhM1M4E/S8QLeGyf6MkDV/pWgjQ0tdTSyQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.x"
|
||||
}
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
@@ -1414,6 +1811,19 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eta": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/eta/-/eta-3.5.0.tgz",
|
||||
"integrity": "sha512-e3x3FBvGzeCIHhF+zhK8FZA2vC5uFn6b4HJjegUbIWrDb4mJ7JjTGMJY9VGIbRVpmSwHopNiaJibhjIr+HfLug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/eta-dev/eta?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/eventemitter3": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
@@ -1852,6 +2262,16 @@
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/header-range-parser": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/header-range-parser/-/header-range-parser-1.1.3.tgz",
|
||||
"integrity": "sha512-B9zCFt3jH8g09LR1vHL4pcAn8yMEtlSlOUdQemzHMRKMImNIhhszdeosYFfNW0WXKQtXIlWB+O4owHJKvEJYaA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.22.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hosted-git-info": {
|
||||
"version": "2.8.9",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
|
||||
@@ -1935,6 +2355,13 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/http-status-emojis": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-status-emojis/-/http-status-emojis-2.2.0.tgz",
|
||||
"integrity": "sha512-ompKtgwpx8ff0hsbpIB7oE4ax1LXoHmftsHHStMELX56ivG3GhofTX8ZHWlUaFKfGjcGjw6G3rPk7dJRXMmbbg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
@@ -1985,6 +2412,16 @@
|
||||
"node": ">=0.8.19"
|
||||
}
|
||||
},
|
||||
"node_modules/inflection": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/inflection/-/inflection-3.0.2.tgz",
|
||||
"integrity": "sha512-+Bg3+kg+J6JUWn8J6bzFmOWkTQ6L/NHfDRSYU+EVvuKHDxUDHAXgqixHfVlzuBQaPOTac8hn43aPhMNk6rMe3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
@@ -2019,6 +2456,16 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz",
|
||||
"integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-array-buffer": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
||||
@@ -2452,6 +2899,60 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-server": {
|
||||
"version": "1.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/json-server/-/json-server-1.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-DwE69Ep5ccwIJZBUIWEENC30Yj8bwr4Ax9W9VoIWAYnB8Sj4ReptscO8/DRHv/nXwVlmb3Bk73Ls86+VZdYkkA==",
|
||||
"dev": true,
|
||||
"license": "SEE LICENSE IN ./LICENSE",
|
||||
"dependencies": {
|
||||
"@tinyhttp/app": "^2.4.0",
|
||||
"@tinyhttp/cors": "^2.0.1",
|
||||
"@tinyhttp/logger": "^2.0.0",
|
||||
"chalk": "^5.3.0",
|
||||
"chokidar": "^4.0.1",
|
||||
"dot-prop": "^9.0.0",
|
||||
"eta": "^3.5.0",
|
||||
"inflection": "^3.0.0",
|
||||
"json5": "^2.2.3",
|
||||
"lowdb": "^7.0.1",
|
||||
"milliparsec": "^4.0.0",
|
||||
"sirv": "^2.0.4",
|
||||
"sort-on": "^6.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"json-server": "lib/bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.3"
|
||||
}
|
||||
},
|
||||
"node_modules/json-server/node_modules/chalk": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
|
||||
"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/json-server/node_modules/json5": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/json-stable-stringify-without-jsonify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
|
||||
@@ -2535,6 +3036,22 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lowdb": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lowdb/-/lowdb-7.0.1.tgz",
|
||||
"integrity": "sha512-neJAj8GwF0e8EpycYIDFqEPcx9Qz4GUho20jWFR7YiFeXzF1YMLdxB36PypcTSPMA+4+LvgyMacYhlr18Zlymw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"steno": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/typicode"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@@ -2554,6 +3071,16 @@
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/milliparsec": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/milliparsec/-/milliparsec-4.0.0.tgz",
|
||||
"integrity": "sha512-/wk9d4Z6/9ZvoEH/6BI4TrTCgmkpZPuSRN/6fI9aUHOfXdNTuj/VhLS7d+NqG26bi6L9YmGXutVYvWC8zQ0qtA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
@@ -2590,6 +3117,25 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/mrmime": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
||||
"integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -2623,6 +3169,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "0.6.4",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
|
||||
"integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/nice-try": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
@@ -3293,6 +3849,20 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/reflect.getprototypeof": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
|
||||
@@ -3337,6 +3907,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/regexparam": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/regexparam/-/regexparam-2.0.2.tgz",
|
||||
"integrity": "sha512-A1PeDEYMrkLrfyOwv2jwihXbo9qxdGD3atBYQA9JJgreAx8/7rC6IUkWOw2NQlOxLp2wL0ifQbh1HuidDfYA6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
@@ -3714,6 +4294,37 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/sirv": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
|
||||
"integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@polka/url": "^1.0.0-next.24",
|
||||
"mrmime": "^2.0.0",
|
||||
"totalist": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/sort-on": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/sort-on/-/sort-on-6.1.0.tgz",
|
||||
"integrity": "sha512-WTECP0nYNWO1n2g5bpsV0yZN9cBmZsF8ThHFbOqVN0HBFRoaQZLLEMvMmJlKHNPYQeVngeI5+jJzIfFqOIo1OA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dot-prop": "^9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
@@ -3760,6 +4371,19 @@
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/steno": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/steno/-/steno-4.0.2.tgz",
|
||||
"integrity": "sha512-yhPIQXjrlt1xv7dyPQg2P17URmXbuM5pdGkpiMB3RenprfiBlvK415Lctfe0eshk90oA7/tNq7WEiMK8RSP39A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/typicode"
|
||||
}
|
||||
},
|
||||
"node_modules/string.prototype.padend": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz",
|
||||
@@ -3924,6 +4548,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/totalist": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
||||
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
|
||||
|
||||
8
node_modules/.vite/deps/_metadata.json
generated
vendored
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"hash": "761ccfbc",
|
||||
"configHash": "efa0c127",
|
||||
"lockfileHash": "9124da8c",
|
||||
"browserHash": "1c8e9837",
|
||||
"hash": "6ddd1b63",
|
||||
"configHash": "25cf0a03",
|
||||
"lockfileHash": "29e56d0d",
|
||||
"browserHash": "aef01c56",
|
||||
"optimized": {},
|
||||
"chunks": {}
|
||||
}
|
||||
49
node_modules/@polka/url/build.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
const qs = require('querystring');
|
||||
|
||||
/**
|
||||
* @typedef ParsedURL
|
||||
* @type {import('.').ParsedURL}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef Request
|
||||
* @property {string} url
|
||||
* @property {ParsedURL} _parsedUrl
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Request} req
|
||||
* @returns {ParsedURL|void}
|
||||
*/
|
||||
function parse(req) {
|
||||
let raw = req.url;
|
||||
if (raw == null) return;
|
||||
|
||||
let prev = req._parsedUrl;
|
||||
if (prev && prev.raw === raw) return prev;
|
||||
|
||||
let pathname=raw, search='', query, hash;
|
||||
|
||||
if (raw.length > 1) {
|
||||
let idx = raw.indexOf('#', 1);
|
||||
|
||||
if (idx !== -1) {
|
||||
hash = raw.substring(idx);
|
||||
pathname = raw.substring(0, idx);
|
||||
}
|
||||
|
||||
idx = pathname.indexOf('?', 1);
|
||||
|
||||
if (idx !== -1) {
|
||||
search = pathname.substring(idx);
|
||||
pathname = pathname.substring(0, idx);
|
||||
if (search.length > 1) {
|
||||
query = qs.parse(search.substring(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return req._parsedUrl = { pathname, search, query, hash, raw };
|
||||
}
|
||||
|
||||
exports.parse = parse;
|
||||
47
node_modules/@polka/url/build.mjs
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
import * as qs from 'node:querystring';
|
||||
|
||||
/**
|
||||
* @typedef ParsedURL
|
||||
* @type {import('.').ParsedURL}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef Request
|
||||
* @property {string} url
|
||||
* @property {ParsedURL} _parsedUrl
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Request} req
|
||||
* @returns {ParsedURL|void}
|
||||
*/
|
||||
export function parse(req) {
|
||||
let raw = req.url;
|
||||
if (raw == null) return;
|
||||
|
||||
let prev = req._parsedUrl;
|
||||
if (prev && prev.raw === raw) return prev;
|
||||
|
||||
let pathname=raw, search='', query, hash;
|
||||
|
||||
if (raw.length > 1) {
|
||||
let idx = raw.indexOf('#', 1);
|
||||
|
||||
if (idx !== -1) {
|
||||
hash = raw.substring(idx);
|
||||
pathname = raw.substring(0, idx);
|
||||
}
|
||||
|
||||
idx = pathname.indexOf('?', 1);
|
||||
|
||||
if (idx !== -1) {
|
||||
search = pathname.substring(idx);
|
||||
pathname = pathname.substring(0, idx);
|
||||
if (search.length > 1) {
|
||||
query = qs.parse(search.substring(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return req._parsedUrl = { pathname, search, query, hash, raw };
|
||||
}
|
||||
11
node_modules/@polka/url/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { IncomingMessage } from 'http';
|
||||
|
||||
export interface ParsedURL {
|
||||
pathname: string;
|
||||
search: string;
|
||||
query: Record<string, string | string[]> | undefined;
|
||||
hash: string | undefined;
|
||||
raw: string;
|
||||
}
|
||||
|
||||
export function parse(req: IncomingMessage): ParsedURL;
|
||||
30
node_modules/@polka/url/package.json
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"version": "1.0.0-next.29",
|
||||
"name": "@polka/url",
|
||||
"repository": "lukeed/polka",
|
||||
"description": "Super fast, memoized `req.url` parser",
|
||||
"module": "build.mjs",
|
||||
"types": "index.d.ts",
|
||||
"main": "build.js",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./build.mjs",
|
||||
"require": "./build.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"build.*",
|
||||
"index.d.*"
|
||||
],
|
||||
"author": {
|
||||
"name": "Luke Edwards",
|
||||
"email": "luke@lukeed.com",
|
||||
"url": "https://lukeed.com"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
68
node_modules/@polka/url/readme.md
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
# @polka/url [](https://npmjs.org/package/@polka/url) [](https://licenses.dev/npm/%40polka%2Furl)
|
||||
|
||||
> Super fast, memoized `req.url` parser; _not_ limited to [Polka][polka]!
|
||||
|
||||
Parses the `url` from a [`IncomingMessage`](https://nodejs.org/api/http.html#http_class_http_incomingmessage) request. The returned object will always only contain the following keys: `search`, `query`, `pathname`, and `raw`.
|
||||
|
||||
> **Note:** This library does not process `protocol`, `hostname`, `port`, etc.<br>This is because the incoming `req.url` value only begins with the path information.
|
||||
|
||||
Parsed requests will be mutated with a `_parsedUrl` key, containing the returned output. This is used for future memoization, avoiding the need to fully parse the same `url` value multiple times.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
$ npm install --save @polka/url
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const parse = require('@polka/url');
|
||||
|
||||
let req = {
|
||||
url: '/foo/bar?fizz=buzz'
|
||||
};
|
||||
let output = parse(req);
|
||||
//=> {
|
||||
//=> pathname: '/foo/bar',
|
||||
//=> raw: '/foo/bar?fizz=buzz',
|
||||
//=> search: '?fizz=buzz',
|
||||
//=> query: {
|
||||
//=> fizz: 'buzz'
|
||||
//=> },
|
||||
//=> }
|
||||
|
||||
// Attaches result for future memoization
|
||||
assert.deepEqual(output, req._parsedUrl); //=> true
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### url(req)
|
||||
Returns: `Object` or `undefined`
|
||||
|
||||
> **Important:** The `req` must have a `url` key, otherwise `undefined` will be returned.<br>If no input is provided at all, a `TypeError` will be thrown.
|
||||
|
||||
#### req
|
||||
Type: `IncomingMessage` or `{ url: string }`
|
||||
|
||||
The incoming HTTP request (`req`) or a plain `Object` with a `url` key.
|
||||
|
||||
> **Note:** In Node.js servers, the [`req.url`](https://nodejs.org/api/http.html#http_message_url) begins with a pathname & does not include a `hash`.
|
||||
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Check out the [`bench`](/bench) directory for in-depth benchmark results and comparisons.
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
Any issues or questions can be sent to the [Polka][polka] repository.<br>However, please specify that your inquiry is about `@polka/url` specifically.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
MIT © [Luke Edwards](https://lukeed.com)
|
||||
|
||||
[polka]: https://github.com/lukeed/polka
|
||||
21
node_modules/@tinyhttp/accepts/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 v 1 r t l
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
117
node_modules/@tinyhttp/accepts/README.md
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
# @tinyhttp/accepts
|
||||
|
||||
> [`accepts`](https://github.com/jshttp/accepts) rewrite in TypeScript.
|
||||
|
||||
Higher level content negotiation based on
|
||||
[negotiator](https://www.npmjs.com/package/negotiator). Extracted from
|
||||
[koa](https://www.npmjs.com/package/koa) for general use.
|
||||
|
||||
In addition to negotiator, it allows:
|
||||
|
||||
- Allows types as an array or arguments list, ie
|
||||
`(['text/html', 'application/json'])` as well as
|
||||
`('text/html', 'application/json')`.
|
||||
- Allows type shorthands such as `json`.
|
||||
- Returns `false` when no types match
|
||||
- Treats non-existent headers as `*`
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
pnpm i @tinyhttp/accepts
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```ts
|
||||
import { Accepts } from '@tinyhttp/accepts'
|
||||
```
|
||||
|
||||
### accepts(req)
|
||||
|
||||
Create a new `Accepts` object for the given `req`.
|
||||
|
||||
#### `.charset(charsets)`
|
||||
|
||||
Return the first accepted charset. If nothing in `charsets` is accepted, then
|
||||
`false` is returned.
|
||||
|
||||
#### `.charsets()`
|
||||
|
||||
Return the charsets that the request accepts, in the order of the client's
|
||||
preference (most preferred first).
|
||||
|
||||
#### `.encoding(encodings)`
|
||||
|
||||
Return the first accepted encoding. If nothing in `encodings` is accepted, then
|
||||
`false` is returned.
|
||||
|
||||
#### `.encodings()`
|
||||
|
||||
Return the encodings that the request accepts, in the order of the client's
|
||||
preference (most preferred first).
|
||||
|
||||
#### `.language(languages)`
|
||||
|
||||
Return the first accepted language. If nothing in `languages` is accepted, then
|
||||
`false` is returned.
|
||||
|
||||
#### `.languages()`
|
||||
|
||||
Return the languages that the request accepts, in the order of the client's
|
||||
preference (most preferred first).
|
||||
|
||||
#### `.type(types)`
|
||||
|
||||
Return the first accepted type (and it is returned as the same text as what
|
||||
appears in the `types` array). If nothing in `types` is accepted, then `false`
|
||||
is returned.
|
||||
|
||||
The `types` array can contain full MIME types or file extensions. Any value that
|
||||
is not a full MIME types is passed to `require('mime-types').lookup`.
|
||||
|
||||
#### `.types()`
|
||||
|
||||
Return the types that the request accepts, in the order of the client's
|
||||
preference (most preferred first).
|
||||
|
||||
## Example
|
||||
|
||||
This simple example shows how to use `accepts` to return a different typed
|
||||
respond body based on what the client wants to accept. The server lists it's
|
||||
preferences in order and will get back the best match between the client and
|
||||
server.
|
||||
|
||||
```ts
|
||||
import Accepts from '@tinyhttp/accepts'
|
||||
import { createServer } from 'node:http'
|
||||
|
||||
createServer((req, res) => {
|
||||
const accept = new Accepts(req)
|
||||
|
||||
// the order of this list is significant; should be server preferred order
|
||||
switch (accept.type(['json', 'html'])) {
|
||||
case 'json':
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
res.write('{"hello":"world!"}')
|
||||
break
|
||||
case 'html':
|
||||
res.setHeader('Content-Type', 'text/html')
|
||||
res.write('<b>hello, world!</b>')
|
||||
break
|
||||
default:
|
||||
// the fallback is text/plain, so no need to specify it above
|
||||
res.setHeader('Content-Type', 'text/plain')
|
||||
res.write('hello, world!')
|
||||
break
|
||||
}
|
||||
|
||||
res.end()
|
||||
}).listen(3000)
|
||||
```
|
||||
|
||||
You can test this out with the cURL program:
|
||||
|
||||
```sh
|
||||
curl -I -H 'Accept: text/html' http://localhost:3000/
|
||||
```
|
||||
48
node_modules/@tinyhttp/accepts/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import type { IncomingMessage as I, IncomingHttpHeaders } from 'node:http';
|
||||
import Negotiator from 'negotiator';
|
||||
export declare class Accepts {
|
||||
headers: IncomingHttpHeaders;
|
||||
negotiator: Negotiator;
|
||||
constructor(req: Pick<I, 'headers'>);
|
||||
/**
|
||||
* Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `false`, in which case you should respond with 406 "Not Acceptable".
|
||||
*
|
||||
* The `type` value may be a single mime type string such as "application/json", the extension name such as "json" or an array `["json", "html", "text/plain"]`. When a list or array is given the _best_ match, if any is returned. When no types are given as arguments, returns all types accepted by the client in the preference order.
|
||||
*/
|
||||
types(types: string | string[], ...args: string[]): string[] | string | false;
|
||||
get type(): (types: string | string[], ...args: string[]) => string[] | string | false;
|
||||
/**
|
||||
* Return accepted encodings or best fit based on `encodings`.
|
||||
*
|
||||
* Given `Accept-Encoding: gzip, deflate`
|
||||
* an array sorted by quality is returned:
|
||||
*
|
||||
* ['gzip', 'deflate']
|
||||
*/
|
||||
encodings(encodings: string | string[], ...args: string[]): string | string[] | boolean;
|
||||
get encoding(): (encodings: string | string[], ...args: string[]) => string | string[] | boolean;
|
||||
/**
|
||||
* Return accepted charsets or best fit based on `charsets`.
|
||||
*
|
||||
* Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
|
||||
* an array sorted by quality is returned:
|
||||
*
|
||||
* ['utf-8', 'utf-7', 'iso-8859-1']
|
||||
*/
|
||||
charsets(charsets?: string | string[], ...args: string[]): string | string[] | boolean;
|
||||
get charset(): (charsets: string | string[], ...args: string[]) => string | string[] | boolean;
|
||||
/**
|
||||
* Return accepted languages or best fit based on `langs`.
|
||||
*
|
||||
* Given `Accept-Language: en;q=0.8, es, pt`
|
||||
* an array sorted by quality is returned:
|
||||
*
|
||||
* ['es', 'pt', 'en']
|
||||
*
|
||||
*/
|
||||
languages(languages: string | string[], ...args: string[]): string | string[] | boolean;
|
||||
get lang(): (languages: string | string[], ...args: string[]) => string | string[] | boolean;
|
||||
get langs(): (languages: string | string[], ...args: string[]) => string | string[] | boolean;
|
||||
get language(): (languages: string | string[], ...args: string[]) => string | string[] | boolean;
|
||||
}
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
node_modules/@tinyhttp/accepts/dist/index.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,IAAI,CAAC,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAE1E,OAAO,UAAU,MAAM,YAAY,CAAA;AAMnC,qBAAa,OAAO;IAClB,OAAO,EAAE,mBAAmB,CAAA;IAC5B,UAAU,EAAE,UAAU,CAAA;gBACV,GAAG,EAAE,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC;IAInC;;;;OAIG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,KAAK;IA0B7E,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,GAAG,MAAM,GAAG,KAAK,CAErF;IACD;;;;;;;OAOG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO;IAevF,IAAI,QAAQ,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAE/F;IACD;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO;IAetF,IAAI,OAAO,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAE7F;IACD;;;;;;;;OAQG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO;IAevF,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAE3F;IACD,IAAI,KAAK,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAE5F;IACD,IAAI,QAAQ,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAE/F;CACF"}
|
||||
117
node_modules/@tinyhttp/accepts/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
import mime from 'mime';
|
||||
import Negotiator from 'negotiator';
|
||||
const extToMime = (type) => (type.indexOf('/') === -1 ? mime.getType(type) : type);
|
||||
const validMime = (type) => typeof type === 'string';
|
||||
export class Accepts {
|
||||
constructor(req) {
|
||||
this.headers = req.headers;
|
||||
this.negotiator = new Negotiator(req);
|
||||
}
|
||||
/**
|
||||
* Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `false`, in which case you should respond with 406 "Not Acceptable".
|
||||
*
|
||||
* The `type` value may be a single mime type string such as "application/json", the extension name such as "json" or an array `["json", "html", "text/plain"]`. When a list or array is given the _best_ match, if any is returned. When no types are given as arguments, returns all types accepted by the client in the preference order.
|
||||
*/
|
||||
types(types, ...args) {
|
||||
let mimeTypes = [];
|
||||
// support flattened arguments
|
||||
if (types && !Array.isArray(types)) {
|
||||
mimeTypes = [types, ...args];
|
||||
}
|
||||
else if (types) {
|
||||
mimeTypes = [...types, ...args];
|
||||
}
|
||||
// no types, return all requested types
|
||||
if (!mimeTypes || mimeTypes.length === 0) {
|
||||
return this.negotiator.mediaTypes();
|
||||
}
|
||||
// no accept header, return first given type
|
||||
if (!this.headers.accept) {
|
||||
return mimeTypes[0];
|
||||
}
|
||||
const mimes = mimeTypes.map(extToMime);
|
||||
const accepts = this.negotiator.mediaTypes(mimes.filter(validMime));
|
||||
const [first] = accepts;
|
||||
return first ? mimeTypes[mimes.indexOf(first)] : false;
|
||||
}
|
||||
get type() {
|
||||
return this.types;
|
||||
}
|
||||
/**
|
||||
* Return accepted encodings or best fit based on `encodings`.
|
||||
*
|
||||
* Given `Accept-Encoding: gzip, deflate`
|
||||
* an array sorted by quality is returned:
|
||||
*
|
||||
* ['gzip', 'deflate']
|
||||
*/
|
||||
encodings(encodings, ...args) {
|
||||
let _encodings = encodings;
|
||||
// support flattened arguments
|
||||
if (_encodings && !Array.isArray(_encodings)) {
|
||||
_encodings = [_encodings, ...args];
|
||||
}
|
||||
// no encodings, return all requested encodings
|
||||
if (!_encodings || _encodings.length === 0) {
|
||||
return this.negotiator.encodings();
|
||||
}
|
||||
return this.negotiator.encodings(_encodings)[0] || false;
|
||||
}
|
||||
get encoding() {
|
||||
return this.encodings;
|
||||
}
|
||||
/**
|
||||
* Return accepted charsets or best fit based on `charsets`.
|
||||
*
|
||||
* Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
|
||||
* an array sorted by quality is returned:
|
||||
*
|
||||
* ['utf-8', 'utf-7', 'iso-8859-1']
|
||||
*/
|
||||
charsets(charsets, ...args) {
|
||||
let _charsets = charsets;
|
||||
// support flattened arguments
|
||||
if (_charsets && !Array.isArray(_charsets)) {
|
||||
_charsets = [_charsets, ...args];
|
||||
}
|
||||
// no charsets, return all requested charsets
|
||||
if (!_charsets || _charsets.length === 0) {
|
||||
return this.negotiator.charsets();
|
||||
}
|
||||
return this.negotiator.charsets(_charsets)[0] || false;
|
||||
}
|
||||
get charset() {
|
||||
return this.charsets;
|
||||
}
|
||||
/**
|
||||
* Return accepted languages or best fit based on `langs`.
|
||||
*
|
||||
* Given `Accept-Language: en;q=0.8, es, pt`
|
||||
* an array sorted by quality is returned:
|
||||
*
|
||||
* ['es', 'pt', 'en']
|
||||
*
|
||||
*/
|
||||
languages(languages, ...args) {
|
||||
let _languages = languages;
|
||||
// support flattened arguments
|
||||
if (_languages && !Array.isArray(_languages)) {
|
||||
_languages = [_languages, ...args];
|
||||
}
|
||||
// no languages, return all requested languages
|
||||
if (!_languages || _languages.length === 0) {
|
||||
return this.negotiator.languages();
|
||||
}
|
||||
return this.negotiator.languages(_languages)[0] || false;
|
||||
}
|
||||
get lang() {
|
||||
return this.languages;
|
||||
}
|
||||
get langs() {
|
||||
return this.languages;
|
||||
}
|
||||
get language() {
|
||||
return this.languages;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@tinyhttp/accepts/dist/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
||||
16
node_modules/@tinyhttp/accepts/node_modules/.bin/mime
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../mime/bin/cli.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../mime/bin/cli.js" "$@"
|
||||
fi
|
||||
17
node_modules/@tinyhttp/accepts/node_modules/.bin/mime.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mime\bin\cli.js" %*
|
||||
28
node_modules/@tinyhttp/accepts/node_modules/.bin/mime.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../mime/bin/cli.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../mime/bin/cli.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../mime/bin/cli.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../mime/bin/cli.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
21
node_modules/@tinyhttp/accepts/node_modules/mime/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Robert Kieffer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
143
node_modules/@tinyhttp/accepts/node_modules/mime/README.md
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
<!--
|
||||
-- This file is auto-generated from src/README_js.md. Changes should be made there.
|
||||
-->
|
||||
# Mime
|
||||
|
||||
[](https://www.npmjs.com/package/mime)
|
||||
[](https://github.com/broofa/mime/actions/workflows/ci.yml?query=branch%3Amain)
|
||||
|
||||
An API for MIME type information.
|
||||
|
||||
- All `mime-db` types
|
||||
- Compact and dependency-free [](https://bundlejs.com/?q=mime)
|
||||
- Full TS support
|
||||
|
||||
|
||||
> [!Note]
|
||||
> `mime@4` is now `latest`. If you're upgrading from `mime@3`, note the following:
|
||||
> * `mime@4` is API-compatible with `mime@3`, with ~~one~~ two exceptions:
|
||||
> * Direct imports of `mime` properties [no longer supported](https://github.com/broofa/mime/issues/295)
|
||||
> * `mime.define()` cannot be called on the default `mime` object
|
||||
> * ESM module support is required. [ESM Module FAQ](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
|
||||
> * Requires an [ES2020](https://caniuse.com/?search=es2020) or newer runtime
|
||||
> * Built-in Typescript types (`@types/mime` no longer needed)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install mime
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
For the full version (800+ MIME types, 1,000+ extensions):
|
||||
|
||||
```javascript
|
||||
import mime from 'mime';
|
||||
|
||||
mime.getType('txt'); // ⇨ 'text/plain'
|
||||
mime.getExtension('text/plain'); // ⇨ 'txt'
|
||||
```
|
||||
|
||||
### Lite Version [](https://bundlejs.com/?q=mime/lite)
|
||||
|
||||
`mime/lite` is a drop-in `mime` replacement, stripped of unofficial ("`prs.*`", "`x-*`", "`vnd.*`") types:
|
||||
|
||||
```javascript
|
||||
import mime from 'mime/lite';
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `mime.getType(pathOrExtension)`
|
||||
|
||||
Get mime type for the given file path or extension. E.g.
|
||||
|
||||
```javascript
|
||||
mime.getType('js'); // ⇨ 'text/javascript'
|
||||
mime.getType('json'); // ⇨ 'application/json'
|
||||
|
||||
mime.getType('txt'); // ⇨ 'text/plain'
|
||||
mime.getType('dir/text.txt'); // ⇨ 'text/plain'
|
||||
mime.getType('dir\\text.txt'); // ⇨ 'text/plain'
|
||||
mime.getType('.text.txt'); // ⇨ 'text/plain'
|
||||
mime.getType('.txt'); // ⇨ 'text/plain'
|
||||
```
|
||||
|
||||
`null` is returned in cases where an extension is not detected or recognized
|
||||
|
||||
```javascript
|
||||
mime.getType('foo/txt'); // ⇨ null
|
||||
mime.getType('bogus_type'); // ⇨ null
|
||||
```
|
||||
|
||||
### `mime.getExtension(type)`
|
||||
|
||||
Get file extension for the given mime type. Charset options (often included in Content-Type headers) are ignored.
|
||||
|
||||
```javascript
|
||||
mime.getExtension('text/plain'); // ⇨ 'txt'
|
||||
mime.getExtension('application/json'); // ⇨ 'json'
|
||||
mime.getExtension('text/html; charset=utf8'); // ⇨ 'html'
|
||||
```
|
||||
|
||||
### `mime.getAllExtensions(type)`
|
||||
|
||||
> [!Note]
|
||||
> New in `mime@4`
|
||||
|
||||
Get all file extensions for the given mime type.
|
||||
|
||||
```javascript --run default
|
||||
mime.getAllExtensions('image/jpeg'); // ⇨ Set(3) { 'jpeg', 'jpg', 'jpe' }
|
||||
```
|
||||
|
||||
## Custom `Mime` instances
|
||||
|
||||
The default `mime` objects are immutable. Custom, mutable versions can be created as follows...
|
||||
### new Mime(type map [, type map, ...])
|
||||
|
||||
Create a new, custom mime instance. For example, to create a mutable version of the default `mime` instance:
|
||||
|
||||
```javascript
|
||||
import { Mime } from 'mime/lite';
|
||||
|
||||
import standardTypes from 'mime/types/standard.js';
|
||||
import otherTypes from 'mime/types/other.js';
|
||||
|
||||
const mime = new Mime(standardTypes, otherTypes);
|
||||
```
|
||||
|
||||
Each argument is passed to the `define()` method, below. For example `new Mime(standardTypes, otherTypes)` is synonomous with `new Mime().define(standardTypes).define(otherTypes)`
|
||||
|
||||
### `mime.define(type map [, force = false])`
|
||||
|
||||
> [!Note]
|
||||
> Only available on custom `Mime` instances
|
||||
|
||||
Define MIME type -> extensions.
|
||||
|
||||
Attempting to map a type to an already-defined extension will `throw` unless the `force` argument is set to `true`.
|
||||
|
||||
```javascript
|
||||
mime.define({'text/x-abc': ['abc', 'abcd']});
|
||||
|
||||
mime.getType('abcd'); // ⇨ 'text/x-abc'
|
||||
mime.getExtension('text/x-abc') // ⇨ 'abc'
|
||||
```
|
||||
|
||||
## Command Line
|
||||
|
||||
### Extension -> type
|
||||
|
||||
```bash
|
||||
$ mime scripts/jquery.js
|
||||
text/javascript
|
||||
```
|
||||
|
||||
### Type -> extension
|
||||
|
||||
```bash
|
||||
$ mime -r image/jpeg
|
||||
jpeg
|
||||
```
|
||||
6
node_modules/@tinyhttp/accepts/node_modules/mime/bin/cli.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Thin wrapper around mime
|
||||
import mime_cli from '../dist/src/mime_cli.js';
|
||||
|
||||
await mime_cli();
|
||||
17
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/Mime.d.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
type TypeMap = {
|
||||
[key: string]: string[];
|
||||
};
|
||||
export default class Mime {
|
||||
#private;
|
||||
constructor(...args: TypeMap[]);
|
||||
define(typeMap: TypeMap, force?: boolean): this;
|
||||
getType(path: string): string | null;
|
||||
getExtension(type: string): string | null;
|
||||
getAllExtensions(type: string): Set<string> | null;
|
||||
_freeze(): this;
|
||||
_getTestState(): {
|
||||
types: Map<string, string>;
|
||||
extensions: Map<string, string>;
|
||||
};
|
||||
}
|
||||
export {};
|
||||
85
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/Mime.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
||||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
||||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
||||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
||||
};
|
||||
var _Mime_extensionToType, _Mime_typeToExtension, _Mime_typeToExtensions;
|
||||
class Mime {
|
||||
constructor(...args) {
|
||||
_Mime_extensionToType.set(this, new Map());
|
||||
_Mime_typeToExtension.set(this, new Map());
|
||||
_Mime_typeToExtensions.set(this, new Map());
|
||||
for (const arg of args) {
|
||||
this.define(arg);
|
||||
}
|
||||
}
|
||||
define(typeMap, force = false) {
|
||||
for (let [type, extensions] of Object.entries(typeMap)) {
|
||||
type = type.toLowerCase();
|
||||
extensions = extensions.map((ext) => ext.toLowerCase());
|
||||
if (!__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").has(type)) {
|
||||
__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").set(type, new Set());
|
||||
}
|
||||
const allExtensions = __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type);
|
||||
let first = true;
|
||||
for (let extension of extensions) {
|
||||
const starred = extension.startsWith('*');
|
||||
extension = starred ? extension.slice(1) : extension;
|
||||
allExtensions?.add(extension);
|
||||
if (first) {
|
||||
__classPrivateFieldGet(this, _Mime_typeToExtension, "f").set(type, extension);
|
||||
}
|
||||
first = false;
|
||||
if (starred)
|
||||
continue;
|
||||
const currentType = __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(extension);
|
||||
if (currentType && currentType != type && !force) {
|
||||
throw new Error(`"${type} -> ${extension}" conflicts with "${currentType} -> ${extension}". Pass \`force=true\` to override this definition.`);
|
||||
}
|
||||
__classPrivateFieldGet(this, _Mime_extensionToType, "f").set(extension, type);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
getType(path) {
|
||||
if (typeof path !== 'string')
|
||||
return null;
|
||||
const last = path.replace(/^.*[/\\]/, '').toLowerCase();
|
||||
const ext = last.replace(/^.*\./, '').toLowerCase();
|
||||
const hasPath = last.length < path.length;
|
||||
const hasDot = ext.length < last.length - 1;
|
||||
if (!hasDot && hasPath)
|
||||
return null;
|
||||
return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
|
||||
}
|
||||
getExtension(type) {
|
||||
if (typeof type !== 'string')
|
||||
return null;
|
||||
type = type?.split?.(';')[0];
|
||||
return ((type && __classPrivateFieldGet(this, _Mime_typeToExtension, "f").get(type.trim().toLowerCase())) ?? null);
|
||||
}
|
||||
getAllExtensions(type) {
|
||||
if (typeof type !== 'string')
|
||||
return null;
|
||||
return __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type.toLowerCase()) ?? null;
|
||||
}
|
||||
_freeze() {
|
||||
this.define = () => {
|
||||
throw new Error('define() not allowed for built-in Mime objects. See https://github.com/broofa/mime/blob/main/README.md#custom-mime-instances');
|
||||
};
|
||||
Object.freeze(this);
|
||||
for (const extensions of __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").values()) {
|
||||
Object.freeze(extensions);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
_getTestState() {
|
||||
return {
|
||||
types: __classPrivateFieldGet(this, _Mime_extensionToType, "f"),
|
||||
extensions: __classPrivateFieldGet(this, _Mime_typeToExtension, "f"),
|
||||
};
|
||||
}
|
||||
}
|
||||
_Mime_extensionToType = new WeakMap(), _Mime_typeToExtension = new WeakMap(), _Mime_typeToExtensions = new WeakMap();
|
||||
export default Mime;
|
||||
//# sourceMappingURL=Mime.js.map
|
||||
1
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/Mime.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"Mime.js","sourceRoot":"","sources":["../../src/Mime.ts"],"names":[],"mappings":"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"}
|
||||
4
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import Mime from './Mime.js';
|
||||
export { default as Mime } from './Mime.js';
|
||||
declare const _default: Mime;
|
||||
export default _default;
|
||||
6
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import otherTypes from '../types/other.js';
|
||||
import standardTypes from '../types/standard.js';
|
||||
import Mime from './Mime.js';
|
||||
export { default as Mime } from './Mime.js';
|
||||
export default new Mime(standardTypes, otherTypes)._freeze();
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,mBAAmB,CAAC;AAC3C,OAAO,aAAa,MAAM,sBAAsB,CAAC;AACjD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAE5C,eAAe,IAAI,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC"}
|
||||
4
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/index_lite.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import Mime from './Mime.js';
|
||||
export { default as Mime } from './Mime.js';
|
||||
declare const _default: Mime;
|
||||
export default _default;
|
||||
5
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/index_lite.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import standardTypes from '../types/standard.js';
|
||||
import Mime from './Mime.js';
|
||||
export { default as Mime } from './Mime.js';
|
||||
export default new Mime(standardTypes)._freeze();
|
||||
//# sourceMappingURL=index_lite.js.map
|
||||
1
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/index_lite.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index_lite.js","sourceRoot":"","sources":["../../src/index_lite.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,sBAAsB,CAAC;AACjD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAE5C,eAAe,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE,CAAC"}
|
||||
2
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/mime_cli.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env node
|
||||
export default function (): Promise<void>;
|
||||
67
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/mime_cli.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import mime from './index.js';
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
export default async function () {
|
||||
process.title = 'mime';
|
||||
const json = await fs.readFile(path.join(__dirname, '../../package.json'), 'utf-8');
|
||||
const pkg = JSON.parse(json);
|
||||
const args = process.argv.splice(2);
|
||||
if (args.includes('--version') ||
|
||||
args.includes('-v') ||
|
||||
args.includes('--v')) {
|
||||
console.log(pkg.version);
|
||||
process.exit(0);
|
||||
}
|
||||
else if (args.includes('--name') ||
|
||||
args.includes('-n') ||
|
||||
args.includes('--n')) {
|
||||
console.log(pkg.name);
|
||||
process.exit(0);
|
||||
}
|
||||
else if (args.includes('--help') ||
|
||||
args.includes('-h') ||
|
||||
args.includes('--h')) {
|
||||
console.log(pkg.name + ' - ' + pkg.description + '\n');
|
||||
console.log(`Usage:
|
||||
|
||||
mime [flags] [path_or_extension]
|
||||
|
||||
Flags:
|
||||
--help, -h Show this message
|
||||
--version, -v Display the version
|
||||
--name, -n Print the name of the program
|
||||
--reverse, -r Print the extension of the mime type
|
||||
|
||||
Note: the command will exit after it executes if a command is specified
|
||||
The path_or_extension is the path to the file or the extension of the file.
|
||||
|
||||
Examples:
|
||||
mime --help
|
||||
mime --version
|
||||
mime --name
|
||||
mime -v
|
||||
mime --reverse application/text
|
||||
mime src/log.js
|
||||
mime new.py
|
||||
mime foo.sh
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
else if (args.includes('--reverse') || args.includes('-r')) {
|
||||
const mimeType = args[args.length - 1];
|
||||
const extension = mime.getExtension(mimeType);
|
||||
if (!extension)
|
||||
process.exit(1);
|
||||
process.stdout.write(extension + '\n');
|
||||
process.exit(0);
|
||||
}
|
||||
const file = args[0];
|
||||
const type = mime.getType(file);
|
||||
if (!type)
|
||||
process.exit(1);
|
||||
process.stdout.write(type + '\n');
|
||||
}
|
||||
//# sourceMappingURL=mime_cli.js.map
|
||||
1
node_modules/@tinyhttp/accepts/node_modules/mime/dist/src/mime_cli.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"mime_cli.js","sourceRoot":"","sources":["../../src/mime_cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,YAAY,CAAC;AAE9B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,MAAM,CAAC,OAAO,CAAC,KAAK;IAClB,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC;IAMvB,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAC5B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAC1C,OAAO,CACR,CAAC;IACF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAE7B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAEpC,IACE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC1B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QACnB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EACpB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;SAAM,IACL,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QACnB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EACpB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;SAAM,IACL,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QACnB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EACpB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,GAAG,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;GAsBb,CAAC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAE9C,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEhC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACrB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;AACpC,CAAC"}
|
||||
4
node_modules/@tinyhttp/accepts/node_modules/mime/dist/types/other.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare const types: {
|
||||
[key: string]: string[];
|
||||
};
|
||||
export default types;
|
||||
4
node_modules/@tinyhttp/accepts/node_modules/mime/dist/types/other.js
generated
vendored
Normal file
1
node_modules/@tinyhttp/accepts/node_modules/mime/dist/types/other.js.map
generated
vendored
Normal file
4
node_modules/@tinyhttp/accepts/node_modules/mime/dist/types/standard.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare const types: {
|
||||
[key: string]: string[];
|
||||
};
|
||||
export default types;
|
||||
4
node_modules/@tinyhttp/accepts/node_modules/mime/dist/types/standard.js
generated
vendored
Normal file
1
node_modules/@tinyhttp/accepts/node_modules/mime/dist/types/standard.js.map
generated
vendored
Normal file
76
node_modules/@tinyhttp/accepts/node_modules/mime/package.json
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"author": {
|
||||
"name": "Robert Kieffer",
|
||||
"url": "http://github.com/broofa",
|
||||
"email": "robert@broofa.com"
|
||||
},
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"main": "./dist/src/index.js",
|
||||
"exports": {
|
||||
".": "./dist/src/index.js",
|
||||
"./lite": "./dist/src/index_lite.js",
|
||||
"./types/standard.js": "./dist/types/standard.js",
|
||||
"./types/other.js": "./dist/types/other.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"dist/src",
|
||||
"dist/types",
|
||||
"src",
|
||||
"types"
|
||||
],
|
||||
"bin": {
|
||||
"mime": "bin/cli.js"
|
||||
},
|
||||
"contributors": [],
|
||||
"description": "A comprehensive library for mime-type mapping",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/mime-db": "1.*",
|
||||
"@types/mime-types": "2.1.4",
|
||||
"@types/node": "20.14.10",
|
||||
"@typescript-eslint/eslint-plugin": "7.15.0",
|
||||
"@typescript-eslint/parser": "7.15.0",
|
||||
"chalk": "5.3.0",
|
||||
"mime-score": "2.0.4",
|
||||
"mime-types": "2.1.35",
|
||||
"prettier": "3.3.2",
|
||||
"runmd": "1.3.9",
|
||||
"standard-version": "9.5.0",
|
||||
"typescript": "5.5.3"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run build:clean && tsc",
|
||||
"build:clean": "rm -fr dist",
|
||||
"build:types": "node dist/scripts/build.js",
|
||||
"build:watch": "npm run build:clean && tsc --watch",
|
||||
"lint": "prettier -c .",
|
||||
"lint:fix": "prettier -w .",
|
||||
"prepublishOnly": "npm run build && npm run build:types && npm test",
|
||||
"release": "# `standard-version --dry-run` is the command you're after",
|
||||
"test": "npm run build && node --test && ./test/exports_test.sh",
|
||||
"test:watch": "clear && node --enable-source-maps --test --watch test"
|
||||
},
|
||||
"keywords": [
|
||||
"extension",
|
||||
"file",
|
||||
"mime",
|
||||
"mime-db",
|
||||
"mimetypes",
|
||||
"util"
|
||||
],
|
||||
"name": "mime",
|
||||
"repository": {
|
||||
"url": "https://github.com/broofa/mime",
|
||||
"type": "git"
|
||||
},
|
||||
"version": "4.0.4",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa"
|
||||
],
|
||||
"packageManager": "npm@10.8.1+sha256.b8807aebb9656758e2872fa6e7c564b506aa2faa9297439a478d471d2fe32483"
|
||||
}
|
||||
137
node_modules/@tinyhttp/accepts/node_modules/mime/src/Mime.ts
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
type TypeMap = { [key: string]: string[] };
|
||||
|
||||
export default class Mime {
|
||||
#extensionToType = new Map<string, string>();
|
||||
#typeToExtension = new Map<string, string>();
|
||||
#typeToExtensions = new Map<string, Set<string>>();
|
||||
|
||||
constructor(...args: TypeMap[]) {
|
||||
for (const arg of args) {
|
||||
this.define(arg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define mimetype -> extension mappings. Each key is a mime-type that maps
|
||||
* to an array of extensions associated with the type. The first extension is
|
||||
* used as the default extension for the type.
|
||||
*
|
||||
* e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']});
|
||||
*
|
||||
* If a mapping for an extension has already been defined an error will be
|
||||
* thrown unless the `force` argument is set to `true`.
|
||||
*
|
||||
* e.g. mime.define({'audio/wav', ['wav']}, {'audio/x-wav', ['*wav']});
|
||||
*/
|
||||
define(typeMap: TypeMap, force = false) {
|
||||
for (let [type, extensions] of Object.entries(typeMap)) {
|
||||
// Lowercase thingz
|
||||
type = type.toLowerCase();
|
||||
extensions = extensions.map((ext) => ext.toLowerCase());
|
||||
|
||||
if (!this.#typeToExtensions.has(type)) {
|
||||
this.#typeToExtensions.set(type, new Set<string>());
|
||||
}
|
||||
const allExtensions = this.#typeToExtensions.get(type);
|
||||
|
||||
let first = true;
|
||||
for (let extension of extensions) {
|
||||
const starred = extension.startsWith('*');
|
||||
|
||||
extension = starred ? extension.slice(1) : extension;
|
||||
|
||||
// Add to list of extensions for the type
|
||||
allExtensions?.add(extension);
|
||||
|
||||
if (first) {
|
||||
// Map type to default extension (first in list)
|
||||
this.#typeToExtension.set(type, extension);
|
||||
}
|
||||
first = false;
|
||||
|
||||
// Starred types are not eligible to be the default extension
|
||||
if (starred) continue;
|
||||
|
||||
// Map extension to type
|
||||
const currentType = this.#extensionToType.get(extension);
|
||||
if (currentType && currentType != type && !force) {
|
||||
throw new Error(
|
||||
`"${type} -> ${extension}" conflicts with "${currentType} -> ${extension}". Pass \`force=true\` to override this definition.`,
|
||||
);
|
||||
}
|
||||
this.#extensionToType.set(extension, type);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mime type associated with an extension
|
||||
*/
|
||||
getType(path: string) {
|
||||
if (typeof path !== 'string') return null;
|
||||
|
||||
// Remove chars preceeding `/` or `\`
|
||||
const last = path.replace(/^.*[/\\]/, '').toLowerCase();
|
||||
|
||||
// Remove chars preceeding '.'
|
||||
const ext = last.replace(/^.*\./, '').toLowerCase();
|
||||
|
||||
const hasPath = last.length < path.length;
|
||||
const hasDot = ext.length < last.length - 1;
|
||||
|
||||
// Extension-less file?
|
||||
if (!hasDot && hasPath) return null;
|
||||
|
||||
return this.#extensionToType.get(ext) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default file extension associated with a mime type
|
||||
*/
|
||||
getExtension(type: string) {
|
||||
if (typeof type !== 'string') return null;
|
||||
|
||||
// Remove http header parameter(s) (specifically, charset)
|
||||
type = type?.split?.(';')[0];
|
||||
|
||||
return (
|
||||
(type && this.#typeToExtension.get(type.trim().toLowerCase())) ?? null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all file extensions associated with a mime type
|
||||
*/
|
||||
getAllExtensions(type: string) {
|
||||
if (typeof type !== 'string') return null;
|
||||
|
||||
return this.#typeToExtensions.get(type.toLowerCase()) ?? null;
|
||||
}
|
||||
|
||||
//
|
||||
// Private API, for internal use only. These APIs may change at any time
|
||||
//
|
||||
|
||||
_freeze() {
|
||||
this.define = () => {
|
||||
throw new Error('define() not allowed for built-in Mime objects. See https://github.com/broofa/mime/blob/main/README.md#custom-mime-instances');
|
||||
};
|
||||
|
||||
Object.freeze(this);
|
||||
|
||||
for (const extensions of this.#typeToExtensions.values()) {
|
||||
Object.freeze(extensions);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
_getTestState() {
|
||||
return {
|
||||
types: this.#extensionToType,
|
||||
extensions: this.#typeToExtension,
|
||||
};
|
||||
}
|
||||
}
|
||||
7
node_modules/@tinyhttp/accepts/node_modules/mime/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import otherTypes from '../types/other.js';
|
||||
import standardTypes from '../types/standard.js';
|
||||
import Mime from './Mime.js';
|
||||
|
||||
export { default as Mime } from './Mime.js';
|
||||
|
||||
export default new Mime(standardTypes, otherTypes)._freeze();
|
||||
6
node_modules/@tinyhttp/accepts/node_modules/mime/src/index_lite.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import standardTypes from '../types/standard.js';
|
||||
import Mime from './Mime.js';
|
||||
|
||||
export { default as Mime } from './Mime.js';
|
||||
|
||||
export default new Mime(standardTypes)._freeze();
|
||||
85
node_modules/@tinyhttp/accepts/node_modules/mime/src/mime_cli.ts
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import mime from './index.js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export default async function () {
|
||||
process.title = 'mime';
|
||||
|
||||
// TODO: Use json imports to access package.json once "import attributes" are
|
||||
// a real, stable thing.
|
||||
//
|
||||
// See https://github.com/tc39/proposal-import-attributes
|
||||
const json = await fs.readFile(
|
||||
path.join(__dirname, '../../package.json'),
|
||||
'utf-8',
|
||||
);
|
||||
const pkg = JSON.parse(json);
|
||||
|
||||
const args = process.argv.splice(2);
|
||||
|
||||
if (
|
||||
args.includes('--version') ||
|
||||
args.includes('-v') ||
|
||||
args.includes('--v')
|
||||
) {
|
||||
console.log(pkg.version);
|
||||
process.exit(0);
|
||||
} else if (
|
||||
args.includes('--name') ||
|
||||
args.includes('-n') ||
|
||||
args.includes('--n')
|
||||
) {
|
||||
console.log(pkg.name);
|
||||
process.exit(0);
|
||||
} else if (
|
||||
args.includes('--help') ||
|
||||
args.includes('-h') ||
|
||||
args.includes('--h')
|
||||
) {
|
||||
console.log(pkg.name + ' - ' + pkg.description + '\n');
|
||||
console.log(`Usage:
|
||||
|
||||
mime [flags] [path_or_extension]
|
||||
|
||||
Flags:
|
||||
--help, -h Show this message
|
||||
--version, -v Display the version
|
||||
--name, -n Print the name of the program
|
||||
--reverse, -r Print the extension of the mime type
|
||||
|
||||
Note: the command will exit after it executes if a command is specified
|
||||
The path_or_extension is the path to the file or the extension of the file.
|
||||
|
||||
Examples:
|
||||
mime --help
|
||||
mime --version
|
||||
mime --name
|
||||
mime -v
|
||||
mime --reverse application/text
|
||||
mime src/log.js
|
||||
mime new.py
|
||||
mime foo.sh
|
||||
`);
|
||||
process.exit(0);
|
||||
} else if (args.includes('--reverse') || args.includes('-r')) {
|
||||
const mimeType = args[args.length - 1];
|
||||
const extension = mime.getExtension(mimeType);
|
||||
|
||||
if (!extension) process.exit(1);
|
||||
|
||||
process.stdout.write(extension + '\n');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const file = args[0];
|
||||
const type = mime.getType(file);
|
||||
|
||||
if (!type) process.exit(1);
|
||||
|
||||
process.stdout.write(type + '\n');
|
||||
}
|
||||
3
node_modules/@tinyhttp/accepts/node_modules/mime/types/other.ts
generated
vendored
Normal file
3
node_modules/@tinyhttp/accepts/node_modules/mime/types/standard.ts
generated
vendored
Normal file
35
node_modules/@tinyhttp/accepts/package.json
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "@tinyhttp/accepts",
|
||||
"description": "accepts rewrite in TypeScript",
|
||||
"version": "2.2.3",
|
||||
"license": "MIT",
|
||||
"homepage": "https://tinyhttp.v1rtl.site",
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/tinyhttp/tinyhttp?sponsor=1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tinyhttp/tinyhttp.git",
|
||||
"directory": "packages/cookie-signature"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
},
|
||||
"type": "module",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": "./dist/index.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/negotiator": "^0.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"mime": "4.0.4",
|
||||
"negotiator": "^0.6.3"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
}
|
||||
}
|
||||
21
node_modules/@tinyhttp/app/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 v 1 r t l
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
25
node_modules/@tinyhttp/app/README.md
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# @tinyhttp/app
|
||||
|
||||
The core of tinyhttp. Contains the `App`, `Request` and `Response`. Additionally, it provides special tinyhttp-specific types.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
pnpm i @tinyhttp/app
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
import { App } from '@tinyhttp/app'
|
||||
import type { Request, Response, NextFunction } from '@tinyhttp/app'
|
||||
|
||||
new App()
|
||||
.use((req: Request, res: Response, next: NextFunction) => {
|
||||
console.log('Did a request')
|
||||
next()
|
||||
})
|
||||
.get('/', (_, res) => res.send('<h1>Hello World</h1>'))
|
||||
.get('/page/:page', (req, res) => res.send(`You opened ${req.params.page}`))
|
||||
.listen(3000)
|
||||
```
|
||||
55
node_modules/@tinyhttp/app/dist/app.d.ts
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
import { type Server } from 'node:http';
|
||||
import type { Handler, Middleware, NextFunction, UseMethodParams } from '@tinyhttp/router';
|
||||
import { Router } from '@tinyhttp/router';
|
||||
import type { TemplateEngineOptions } from './index.js';
|
||||
import type { ErrorHandler } from './onError.js';
|
||||
import type { Request } from './request.js';
|
||||
import type { Response } from './response.js';
|
||||
import type { AppConstructor, AppInterface, AppRenderOptions, AppSettings, TemplateEngine } from './types.js';
|
||||
/**
|
||||
* `App` class - the starting point of tinyhttp app.
|
||||
*
|
||||
* With the `App` you can:
|
||||
* * use routing methods and `.use(...)`
|
||||
* * set no match (404) and error (500) handlers
|
||||
* * configure template engines
|
||||
* * store data in locals
|
||||
* * listen the http server on a specified port
|
||||
*
|
||||
* In case you use TypeScript, you can pass custom types to this class because it is also a generic class.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```ts
|
||||
* interface CoolReq extends Request {
|
||||
* genericsAreDope: boolean
|
||||
* }
|
||||
*
|
||||
* const app = App<any, CoolReq, Response>()
|
||||
* ```
|
||||
*/
|
||||
export declare class App<Req extends Request = Request, Res extends Response = Response> extends Router<App, Req, Res> implements AppInterface<Req, Res> {
|
||||
#private;
|
||||
middleware: Middleware<Req, Res>[];
|
||||
locals: Record<string, unknown>;
|
||||
noMatchHandler: Handler;
|
||||
onError: ErrorHandler;
|
||||
settings: AppSettings;
|
||||
engines: Record<string, TemplateEngine>;
|
||||
applyExtensions?: Handler;
|
||||
attach: (req: Req, res: Res, next?: NextFunction) => void;
|
||||
cache: Record<string, unknown>;
|
||||
constructor(options?: AppConstructor<Req, Res>);
|
||||
set<K extends keyof AppSettings>(setting: K, value: AppSettings[K]): this;
|
||||
enable<K extends keyof AppSettings>(setting: K): this;
|
||||
enabled<K extends keyof AppSettings>(setting: K): boolean;
|
||||
disable<K extends keyof AppSettings>(setting: K): this;
|
||||
path(): any;
|
||||
engine<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions>(ext: string, fn: TemplateEngine<RenderOptions>): this;
|
||||
render<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions>(name: string, data?: Record<string, unknown>, options?: AppRenderOptions<RenderOptions>, cb?: (err: unknown, html?: unknown) => void): void;
|
||||
use(...args: UseMethodParams<Req, Res, AppInterface<any, any>>): this;
|
||||
route(path: string): App<any, any>;
|
||||
handler<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions>(req: Req, res: Res, next?: NextFunction): void;
|
||||
listen(port?: number, cb?: () => void, host?: string): Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>;
|
||||
}
|
||||
//# sourceMappingURL=app.d.ts.map
|
||||
1
node_modules/@tinyhttp/app/dist/app.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
|
||||
323
node_modules/@tinyhttp/app/dist/app.js
generated
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
||||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
||||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
||||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
||||
};
|
||||
var _App_instances, _App_find;
|
||||
import { createServer } from 'node:http';
|
||||
import { getPathname } from '@tinyhttp/req';
|
||||
import { Router, pushMiddleware } from '@tinyhttp/router';
|
||||
import { parse as rg } from 'regexparam';
|
||||
import { extendMiddleware } from './extend.js';
|
||||
import { onErrorHandler } from './onError.js';
|
||||
import { getURLParams } from './request.js';
|
||||
import { View } from './view.js';
|
||||
/**
|
||||
* Add leading slash if not present (e.g. path -> /path, /path -> /path)
|
||||
* @param x
|
||||
*/
|
||||
const lead = (x) => (x.charCodeAt(0) === 47 ? x : `/${x}`);
|
||||
const trail = (x) => (x.charCodeAt(x.length - 1) === 47 ? x.substring(0, x.length - 1) : x);
|
||||
const mount = (fn) => (fn instanceof App ? fn.attach : fn);
|
||||
const applyHandler = (h) => async (req, res, next) => {
|
||||
try {
|
||||
if (h[Symbol.toStringTag] === 'AsyncFunction') {
|
||||
await h(req, res, next);
|
||||
}
|
||||
else
|
||||
h(req, res, next);
|
||||
}
|
||||
catch (e) {
|
||||
next === null || next === void 0 ? void 0 : next(e);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* `App` class - the starting point of tinyhttp app.
|
||||
*
|
||||
* With the `App` you can:
|
||||
* * use routing methods and `.use(...)`
|
||||
* * set no match (404) and error (500) handlers
|
||||
* * configure template engines
|
||||
* * store data in locals
|
||||
* * listen the http server on a specified port
|
||||
*
|
||||
* In case you use TypeScript, you can pass custom types to this class because it is also a generic class.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```ts
|
||||
* interface CoolReq extends Request {
|
||||
* genericsAreDope: boolean
|
||||
* }
|
||||
*
|
||||
* const app = App<any, CoolReq, Response>()
|
||||
* ```
|
||||
*/
|
||||
export class App extends Router {
|
||||
constructor(options = {}) {
|
||||
super();
|
||||
_App_instances.add(this);
|
||||
this.middleware = [];
|
||||
this.locals = {};
|
||||
this.engines = {};
|
||||
this.onError = (options === null || options === void 0 ? void 0 : options.onError) || onErrorHandler;
|
||||
// @ts-expect-error typescript is not smart enough to understand "this" ts(2345)
|
||||
this.noMatchHandler = (options === null || options === void 0 ? void 0 : options.noMatchHandler) || this.onError.bind(this, { code: 404 });
|
||||
this.settings = {
|
||||
view: View,
|
||||
xPoweredBy: true,
|
||||
views: `${process.cwd()}/views`,
|
||||
'view cache': process.env.NODE_ENV === 'production',
|
||||
'trust proxy': 0,
|
||||
...options.settings
|
||||
};
|
||||
if (options.applyExtensions)
|
||||
this.applyExtensions = options === null || options === void 0 ? void 0 : options.applyExtensions;
|
||||
const boundHandler = this.handler.bind(this);
|
||||
this.attach = (req, res, next) => setImmediate(boundHandler, req, res, next);
|
||||
this.cache = {};
|
||||
}
|
||||
set(setting, value) {
|
||||
this.settings[setting] = value;
|
||||
return this;
|
||||
}
|
||||
enable(setting) {
|
||||
this.settings[setting] = true;
|
||||
return this;
|
||||
}
|
||||
enabled(setting) {
|
||||
return Boolean(this.settings[setting]);
|
||||
}
|
||||
disable(setting) {
|
||||
this.settings[setting] = false;
|
||||
return this;
|
||||
}
|
||||
path() {
|
||||
return this.parent ? this.parent.path() + this.mountpath : '';
|
||||
}
|
||||
engine(ext, fn) {
|
||||
this.engines[ext[0] === '.' ? ext : `.${ext}`] = fn;
|
||||
return this;
|
||||
}
|
||||
render(name, data = {}, options = {}, cb = () => { }) {
|
||||
let view;
|
||||
const { _locals, ...opts } = options;
|
||||
let locals = this.locals;
|
||||
if (_locals)
|
||||
locals = { ...locals, ..._locals };
|
||||
locals = { ...locals, ...data };
|
||||
if (opts.cache == null)
|
||||
opts.cache = this.enabled('view cache');
|
||||
if (opts.cache) {
|
||||
view = this.cache[name];
|
||||
}
|
||||
if (!view) {
|
||||
const ViewClass = this.settings.view || View;
|
||||
try {
|
||||
view = new ViewClass(name, {
|
||||
defaultEngine: this.settings['view engine'],
|
||||
root: this.settings.views,
|
||||
engines: this.engines
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
if (opts.cache) {
|
||||
this.cache[name] = view;
|
||||
}
|
||||
}
|
||||
try {
|
||||
view.render(opts, locals, cb);
|
||||
}
|
||||
catch (err) {
|
||||
cb(err);
|
||||
}
|
||||
}
|
||||
use(...args) {
|
||||
var _a;
|
||||
const base = args[0];
|
||||
const fns = args.slice(1).flat();
|
||||
let pathArray = [];
|
||||
if (typeof base === 'function' || base instanceof App) {
|
||||
fns.unshift(base);
|
||||
}
|
||||
else {
|
||||
// if base is not an array of paths, then convert it to an array.
|
||||
let basePaths = [];
|
||||
if (Array.isArray(base))
|
||||
basePaths = base;
|
||||
else if (typeof base === 'string')
|
||||
basePaths = [base];
|
||||
basePaths = basePaths.filter((element) => {
|
||||
if (typeof element === 'string') {
|
||||
pathArray.push(element);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
fns.unshift(...basePaths);
|
||||
}
|
||||
pathArray = pathArray.length ? pathArray.map((path) => lead(path)) : ['/'];
|
||||
const mountpath = pathArray.join(', ');
|
||||
let regex;
|
||||
for (const fn of fns) {
|
||||
if (fn instanceof App) {
|
||||
for (const path of pathArray) {
|
||||
regex = rg(path, true);
|
||||
fn.mountpath = mountpath;
|
||||
this.apps[path] = fn;
|
||||
// @ts-expect-error typescript is not smart enough to understand "this" ts(2345)
|
||||
fn.parent = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const path of pathArray) {
|
||||
const handlerPaths = [];
|
||||
const handlerFunctions = [];
|
||||
const handlerPathBase = path === '/' ? '' : lead(path);
|
||||
for (const fn of fns) {
|
||||
if (fn instanceof App && ((_a = fn.middleware) === null || _a === void 0 ? void 0 : _a.length)) {
|
||||
for (const mw of fn.middleware) {
|
||||
handlerPaths.push(handlerPathBase + lead(mw.path));
|
||||
handlerFunctions.push(fn);
|
||||
}
|
||||
}
|
||||
else {
|
||||
handlerPaths.push('');
|
||||
handlerFunctions.push(fn);
|
||||
}
|
||||
}
|
||||
pushMiddleware(this.middleware)({
|
||||
path,
|
||||
regex,
|
||||
type: 'mw',
|
||||
handler: mount(handlerFunctions[0]),
|
||||
handlers: handlerFunctions.slice(1).map(mount),
|
||||
fullPaths: handlerPaths
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
route(path) {
|
||||
const app = new App({ settings: this.settings });
|
||||
this.use(path, app);
|
||||
return app;
|
||||
}
|
||||
handler(req, res, next) {
|
||||
/* Set X-Powered-By header */
|
||||
const { xPoweredBy } = this.settings;
|
||||
if (xPoweredBy)
|
||||
res.setHeader('X-Powered-By', typeof xPoweredBy === 'string' ? xPoweredBy : 'tinyhttp');
|
||||
// @ts-expect-error typescript is not smart enough to understand "this" ts(2345)
|
||||
const exts = this.applyExtensions || extendMiddleware(this);
|
||||
let mw = [
|
||||
{
|
||||
handler: exts,
|
||||
type: 'mw',
|
||||
path: '/'
|
||||
}
|
||||
];
|
||||
req.baseUrl = '';
|
||||
const handle = (mw, pathname) => async (req, res, next) => {
|
||||
var _a;
|
||||
const { path, handler, regex } = mw;
|
||||
let params;
|
||||
try {
|
||||
params = regex ? getURLParams(regex, pathname) : {};
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
if (e instanceof URIError)
|
||||
return res.sendStatus(400);
|
||||
throw e;
|
||||
}
|
||||
let prefix = path;
|
||||
if (regex) {
|
||||
for (const key of regex.keys) {
|
||||
if (key === 'wild') {
|
||||
prefix = prefix.replace('*', params.wild);
|
||||
}
|
||||
else {
|
||||
prefix = prefix.replace(`:${key}`, params[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
req.params = { ...req.params, ...params };
|
||||
if (mw.type === 'mw') {
|
||||
req.url = lead(req.originalUrl.substring(prefix.length));
|
||||
req.baseUrl = trail(req.originalUrl.substring(0, prefix.length));
|
||||
}
|
||||
if (!req.path)
|
||||
req.path = pathname;
|
||||
if ((_a = this.settings) === null || _a === void 0 ? void 0 : _a.enableReqRoute)
|
||||
req.route = mw;
|
||||
await applyHandler(handler)(req, res, next);
|
||||
};
|
||||
let idx = 0;
|
||||
const loop = () => {
|
||||
req.originalUrl = req.baseUrl + req.url;
|
||||
const pathname = getPathname(req.url);
|
||||
const matched = __classPrivateFieldGet(this, _App_instances, "m", _App_find).call(this, pathname).filter((x) => (req.method === 'HEAD' || (x.method ? x.method === req.method : true)) && !mw.includes(x));
|
||||
if (matched.length && matched[0] !== null) {
|
||||
if (idx !== 0) {
|
||||
idx = mw.length;
|
||||
req.params = {};
|
||||
}
|
||||
mw = [
|
||||
...mw,
|
||||
...matched,
|
||||
{
|
||||
type: 'mw',
|
||||
handler: (req, res, next) => {
|
||||
if (req.method === 'HEAD') {
|
||||
res.statusCode = 204;
|
||||
return res.end('');
|
||||
}
|
||||
next === null || next === void 0 ? void 0 : next();
|
||||
},
|
||||
path: '/'
|
||||
}
|
||||
];
|
||||
}
|
||||
else if (this.parent == null) {
|
||||
mw.push({
|
||||
handler: this.noMatchHandler,
|
||||
type: 'route',
|
||||
path: '/'
|
||||
});
|
||||
}
|
||||
void handle(mw[idx++], pathname)(req, res, next);
|
||||
};
|
||||
const parentNext = next;
|
||||
next = (err) => {
|
||||
if (err != null) {
|
||||
// @ts-expect-error The 'this' context of type 'this' is not assignable to method's 'this' of type 'App<Request, Response<unknown>>' ts(2345)
|
||||
return this.onError(err, req, res);
|
||||
}
|
||||
if (res.writableEnded)
|
||||
return;
|
||||
if (idx >= mw.length) {
|
||||
if (parentNext != null)
|
||||
parentNext();
|
||||
return;
|
||||
}
|
||||
loop();
|
||||
};
|
||||
loop();
|
||||
}
|
||||
listen(port, cb, host) {
|
||||
return createServer().on('request', this.attach).listen(port, host, cb);
|
||||
}
|
||||
}
|
||||
_App_instances = new WeakSet(), _App_find = function _App_find(url) {
|
||||
return this.middleware.filter((m) => {
|
||||
m.regex = m.regex || rg(m.path, m.type === 'mw');
|
||||
let fullPathRegex;
|
||||
m.fullPath && typeof m.fullPath === 'string'
|
||||
? (fullPathRegex = rg(m.fullPath, m.type === 'mw'))
|
||||
: (fullPathRegex = null);
|
||||
return m.regex.pattern.test(url) && (m.type === 'mw' && fullPathRegex ? fullPathRegex.pattern.test(url) : true);
|
||||
});
|
||||
};
|
||||
//# sourceMappingURL=app.js.map
|
||||
1
node_modules/@tinyhttp/app/dist/app.js.map
generated
vendored
Normal file
8
node_modules/@tinyhttp/app/dist/extend.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { App } from './app.js';
|
||||
import type { Handler } from './index.js';
|
||||
import type { TemplateEngineOptions } from './types.js';
|
||||
/**
|
||||
* Extends Request and Response objects with custom properties and methods
|
||||
*/
|
||||
export declare const extendMiddleware: <EngineOptions extends TemplateEngineOptions = TemplateEngineOptions>(app: App) => Handler;
|
||||
//# sourceMappingURL=extend.d.ts.map
|
||||
1
node_modules/@tinyhttp/app/dist/extend.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"extend.d.ts","sourceRoot":"","sources":["../src/extend.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AACnC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAKzC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,aAAa,SAAS,qBAAqB,+BAA+B,GAAG,KA+DtG,OAAO,CAAA"}
|
||||
64
node_modules/@tinyhttp/app/dist/extend.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
import { compile } from '@tinyhttp/proxy-addr';
|
||||
import { checkIfXMLHttpRequest, getAccepts, getAcceptsCharsets, getAcceptsEncodings, getAcceptsLanguages, getFreshOrStale, getQueryParams, getRangeFromHeader, getRequestHeader, reqIs } from '@tinyhttp/req';
|
||||
import { append, attachment, clearCookie, download, formatResponse, getResponseHeader, json, redirect, send, sendFile, sendStatus, setContentType, setCookie, setHeader, setLinksHeader, setLocationHeader, setVaryHeader, status } from '@tinyhttp/res';
|
||||
import { getSubdomains } from './request.js';
|
||||
import { getHost, getIP, getIPs, getProtocol } from './request.js';
|
||||
import { renderTemplate } from './response.js';
|
||||
/**
|
||||
* Extends Request and Response objects with custom properties and methods
|
||||
*/
|
||||
export const extendMiddleware = (app) => ((req, res, next) => {
|
||||
const { settings } = app;
|
||||
res.get = getResponseHeader(res);
|
||||
req.get = getRequestHeader(req);
|
||||
if (settings === null || settings === void 0 ? void 0 : settings.bindAppToReqRes) {
|
||||
req.app = app;
|
||||
res.app = app;
|
||||
}
|
||||
if (settings === null || settings === void 0 ? void 0 : settings.networkExtensions) {
|
||||
let trust = (settings === null || settings === void 0 ? void 0 : settings['trust proxy']) || 0;
|
||||
if (trust && typeof trust !== 'function') {
|
||||
trust = compile(trust);
|
||||
settings['trust proxy'] = trust;
|
||||
}
|
||||
req.protocol = getProtocol(req, trust);
|
||||
req.secure = req.protocol === 'https';
|
||||
const host = getHost(req, trust);
|
||||
req.hostname = host === null || host === void 0 ? void 0 : host.hostname;
|
||||
req.port = host === null || host === void 0 ? void 0 : host.port;
|
||||
req.subdomains = getSubdomains(req, trust, settings.subdomainOffset);
|
||||
req.ip = getIP(req, trust);
|
||||
req.ips = getIPs(req, trust);
|
||||
}
|
||||
req.query = getQueryParams(req.url);
|
||||
req.is = reqIs(req);
|
||||
req.range = getRangeFromHeader(req);
|
||||
req.accepts = getAccepts(req);
|
||||
req.acceptsCharsets = getAcceptsCharsets(req);
|
||||
req.acceptsEncodings = getAcceptsEncodings(req);
|
||||
req.acceptsLanguages = getAcceptsLanguages(req);
|
||||
req.xhr = checkIfXMLHttpRequest(req);
|
||||
res.header = res.set = setHeader(res);
|
||||
res.send = send(req, res);
|
||||
res.json = json(res);
|
||||
res.status = status(res);
|
||||
res.sendStatus = sendStatus(req, res);
|
||||
res.sendFile = sendFile(req, res);
|
||||
res.type = setContentType(res);
|
||||
res.location = setLocationHeader(req, res);
|
||||
res.links = setLinksHeader(res);
|
||||
res.vary = setVaryHeader(res);
|
||||
res.cookie = setCookie(req, res);
|
||||
res.clearCookie = clearCookie(req, res);
|
||||
res.render = renderTemplate(req, res, app);
|
||||
res.format = formatResponse(req, res, next);
|
||||
res.redirect = redirect(req, res, next);
|
||||
res.attachment = attachment(res);
|
||||
res.download = download(req, res);
|
||||
res.append = append(res);
|
||||
res.locals = res.locals || Object.create(null);
|
||||
Object.defineProperty(req, 'fresh', { get: getFreshOrStale.bind(null, req, res), configurable: true });
|
||||
req.stale = !req.fresh;
|
||||
next();
|
||||
});
|
||||
//# sourceMappingURL=extend.js.map
|
||||
1
node_modules/@tinyhttp/app/dist/extend.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"extend.js","sourceRoot":"","sources":["../src/extend.ts"],"names":[],"mappings":"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"}
|
||||
15
node_modules/@tinyhttp/app/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
export { App } from './app.js';
|
||||
export * from './request.js';
|
||||
export * from './response.js';
|
||||
export { extendMiddleware } from './extend.js';
|
||||
export { onErrorHandler, type ErrorHandler } from './onError.js';
|
||||
export { View } from './view.js';
|
||||
export type { AppSettings, TemplateEngineOptions, TemplateEngine, AppConstructor } from './types.js';
|
||||
import type { Middleware, NextFunction, AsyncHandler as RAsyncHandler, Handler as RHandler, SyncHandler as RSyncHandler } from '@tinyhttp/router';
|
||||
import type { Request } from './request.js';
|
||||
import type { Response } from './response.js';
|
||||
export type Handler = RHandler<Request, Response>;
|
||||
export type AsyncHandler = RAsyncHandler<Request, Response>;
|
||||
export type SyncHandler = RSyncHandler<Request, Response>;
|
||||
export type { NextFunction, Middleware, Request, Response };
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
node_modules/@tinyhttp/app/dist/index.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,YAAY,EAAE,WAAW,EAAE,qBAAqB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEpG,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,YAAY,IAAI,aAAa,EAC7B,OAAO,IAAI,QAAQ,EACnB,WAAW,IAAI,YAAY,EAC5B,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;AACjD,MAAM,MAAM,YAAY,GAAG,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;AAC3D,MAAM,MAAM,WAAW,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;AACzD,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
||||
7
node_modules/@tinyhttp/app/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export { App } from './app.js';
|
||||
export * from './request.js';
|
||||
export * from './response.js';
|
||||
export { extendMiddleware } from './extend.js';
|
||||
export { onErrorHandler } from './onError.js';
|
||||
export { View } from './view.js';
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@tinyhttp/app/dist/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAqB,MAAM,cAAc,CAAA;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA"}
|
||||
7
node_modules/@tinyhttp/app/dist/onError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { NextFunction } from '@tinyhttp/router';
|
||||
import type { App } from './app.js';
|
||||
import type { Request } from './request.js';
|
||||
import type { Response } from './response.js';
|
||||
export type ErrorHandler = (this: App, err: any, req: Request, res: Response, next?: NextFunction) => void;
|
||||
export declare const onErrorHandler: ErrorHandler;
|
||||
//# sourceMappingURL=onError.d.ts.map
|
||||
1
node_modules/@tinyhttp/app/dist/onError.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"onError.d.ts","sourceRoot":"","sources":["../src/onError.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AACnC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;AAE1G,eAAO,MAAM,cAAc,EAAE,YAU5B,CAAA"}
|
||||
15
node_modules/@tinyhttp/app/dist/onError.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { STATUS_CODES } from 'node:http';
|
||||
export const onErrorHandler = function (err, _req, res) {
|
||||
if (this.onError === onErrorHandler && this.parent)
|
||||
return this.parent.onError(err, _req, res);
|
||||
if (err instanceof Error)
|
||||
console.error(err);
|
||||
const code = err.code in STATUS_CODES ? err.code : err.status;
|
||||
if (typeof err === 'string' || Buffer.isBuffer(err))
|
||||
res.writeHead(500).end(err);
|
||||
else if (code in STATUS_CODES)
|
||||
res.writeHead(code).end(STATUS_CODES[code]);
|
||||
else
|
||||
res.writeHead(500).end(err.message);
|
||||
};
|
||||
//# sourceMappingURL=onError.js.map
|
||||