11 Commits

Author SHA1 Message Date
7fa9e60bab ЛАБ4 - ВСЁ???? 2025-09-26 21:15:37 +04:00
ae4a4e755f вроде почти все
осталось вывод категорий и состояний
2025-09-26 15:06:01 +04:00
229187dd4e ПРОГРЕСС УРА 2025-09-25 16:29:37 +04:00
632835f834 браузер не видит компоненты, класс! 2025-09-25 01:11:17 +04:00
f7afa74bed похороните меня за плинтусом 2025-09-24 22:26:48 +04:00
205bb0f195 я обязательно досдам... 2025-05-24 16:05:10 +04:00
0ead01438a ты думаешь у меня есть только вера?
болван, мне больше ничего и не надо
2025-05-24 00:38:16 +04:00
1940a8e172 a little fix 2025-05-23 22:29:27 +04:00
801a6cac28 done 2025-05-17 12:54:19 +04:00
684c9d7675 допка сделана 2025-05-17 11:46:00 +04:00
e0cf8ff04b чтобы не потерять 2025-05-17 10:46:25 +04:00
1784 changed files with 159846 additions and 404 deletions

View File

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

View File

@@ -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"
}
}

View File

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

View File

@@ -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>

View File

@@ -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>

View 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
View 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
View 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);
}
}

View 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
View 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
View 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);
}
}

View File

@@ -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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

BIN
dist/assets/ava-DiHUHyvl.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

49
dist/assets/controller-BHzoImTo.js vendored Normal file
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

1
dist/assets/page2-Crmhwurg.js vendored Normal file
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@@ -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
View 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
View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

View File

@@ -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>

View File

@@ -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
View 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
View 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
View 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
View File

@@ -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",

View File

@@ -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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,68 @@
# @polka/url [![npm](https://badgen.now.sh/npm/v/@polka/url)](https://npmjs.org/package/@polka/url) [![licenses](https://licenses.dev/b/npm/%40polka%2Furl)](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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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" %*

View 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

View 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.

View File

@@ -0,0 +1,143 @@
<!--
-- This file is auto-generated from src/README_js.md. Changes should be made there.
-->
# Mime
[![NPM downloads](https://img.shields.io/npm/dm/mime)](https://www.npmjs.com/package/mime)
[![Mime CI](https://github.com/broofa/mime/actions/workflows/ci.yml/badge.svg?branch=main)](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 [![mime's badge](https://deno.bundlejs.com/?q=mime&badge)](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 [![mime/lite's badge](https://deno.bundlejs.com/?q=mime/lite&badge)](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
```

View 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();

View 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 {};

View 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

View File

@@ -0,0 +1 @@
{"version":3,"file":"Mime.js","sourceRoot":"","sources":["../../src/Mime.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,4 @@
import Mime from './Mime.js';
export { default as Mime } from './Mime.js';
declare const _default: Mime;
export default _default;

View 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

View 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"}

View File

@@ -0,0 +1,4 @@
import Mime from './Mime.js';
export { default as Mime } from './Mime.js';
declare const _default: Mime;
export default _default;

View 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

View 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"}

View File

@@ -0,0 +1,2 @@
#!/usr/bin/env node
export default function (): Promise<void>;

View 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

View 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"}

View File

@@ -0,0 +1,4 @@
declare const types: {
[key: string]: string[];
};
export default types;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
declare const types: {
[key: string]: string[];
};
export default types;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,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"
}

View 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,
};
}
}

View 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();

View 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();

View 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');
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

35
node_modules/@tinyhttp/accepts/package.json generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because one or more lines are too long

8
node_modules/@tinyhttp/app/dist/extend.d.ts generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

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