12 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
cdb7405b1f завтра 2025-05-17 01:09:49 +04:00
1794 changed files with 160161 additions and 908 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

@@ -2,61 +2,133 @@
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<title>cyxaruk shop catalog</title>
<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">
<link href="css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="css/styles.css" />
<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="./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>
<div class="header">
<a href="main.html" class="logo">
<img src="img/cyxaruk shop logo.jpg" alt="сухарик шоп">
<h1>cyxaruk shop</h1>
</a>
<ul class="menu">
<li class="dropdown">
<a href="catalog.html">Catalog ▾</a>
<ul class="features-menu">
<li><a href="#">For Men</a></li>
<li><a href="#">For Women</a></li>
<li><a href="#">For Kids</a></li>
<li><a href="#">Order from abroad</a></li>
<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="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>
</li>
<li><a href="contacts.html">Contacts</a></li>
<li><a href="likes.html">Likes</a></li>
<li><a href="basket.html">
<img src="img/basket.png" width="50" height="50" alt="корзина">
</a></li>
</ul>
</div>
<div class="sad">
<h1>Здесь будут лежать твои товары, <br/> а пока здесь так пусто...</h1>
<img src="img/sad1.jpg">
</div>
<div class="footer">
<div class="social-container">
<div class="social">
<a href="https://t.me/cyxarukShop">
<img src="img/telega.png" width="100" height="100" alt="Telegram">
</a>
<h2>← also follow us on tg</h2>
</div>
<div class="social">
<a href="https://www.avito.ru/brands/6f43f8798e9eb61c3350f391762e98b3/all/odezhda_obuv_aksessuary?gdlkerfdnwq=101&page_from=from_item_card&iid=3935618105&sellerId=81d843720716be16ce230bba484bce75">
<img src="img/avito.png" width="80" height="80" alt="Avito">
</a>
<h1>← and avito</h1>
</div>
</div>
<div class="contact-info">
<h2>89876320523</h2>
<h2>Ulyanovsk, Russia</h2>
</nav>
<main class="container my-4">
<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;">
<div class="mt-4">
<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>
<script src="js/bootstrap.bundle.min.js"></script>
<div id="basketContainer"></div>
</main>
<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 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

@@ -2,23 +2,38 @@
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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="node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="node_modules/bootstrap-icons/font/bootstrap-icons.css">
<!-- Минимальные кастомные стили -->
<link rel="stylesheet" href="css/styles.css" />
<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="./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>
<!-- Навигация с использованием Bootstrap -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top">
<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="img/cyxaruk shop logo.jpg" alt="сухарик шоп" width="60" height="60" class="rounded me-2">
<h1 class="h5 mb-0">cyxaruk shop</h1>
<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>
@@ -26,170 +41,410 @@
<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" 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="#">Для мужчин</a></li>
<li><a class="dropdown-item" href="#">Для женщин</a></li>
<li><a class="dropdown-item" href="#">Для детей</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="#">Заказ из-за границы</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">
<a class="nav-link" href="contacts.html">Контакты</a>
<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-fill"></i> Избранное
</a>
<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-fill"></i> Корзина
</a>
<a class="nav-link" href="basket.html"><i class="bi bi-cart me-1"></i>Корзина</a>
</li>
</ul>
</div>
</div>
</nav>
<main class="container mt-5 pt-4">
<!-- Форма для добавления товаров -->
<div class="card mb-4">
<div class="card-body">
<h2 class="card-title">Добавить новый товар</h2>
<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>
<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="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 btn-primary">
<i class="bi bi-plus-circle"></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">
<!-- Товары будут добавляться сюда через JS -->
<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">
<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>
<p class="card-text">super idol rovny pacan,<br> groza rayona, mother's modnik,<br> патч на месте</p>
<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">
<span class="text-muted">$1999.99</span>
<button class="btn btn-sm btn-outline-primary">
<i class="bi bi-cart-plus"></i> В корзину
<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">
<i class="bi bi-heart"></i>
<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>
<i class="bi bi-share"></i> Поделиться
</button>
</div>
</div>
</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>
<!-- Футер -->
<footer class="bg-dark text-white py-4 mt-5">
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
<div class="container">
<div class="row">
<div class="col-md-6">
<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-1"></i>
<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 fs-1"></i>
<i class="bi bi-shop-window fs-2"></i>
</a>
<span>Мы на Авито</span>
</div>
</div>
<div class="col-md-6 text-md-end mt-3 mt-md-0">
<div class="col-md-6 text-md-end">
<h5>Контакты</h5>
<p>89876320523</p>
<p>Ульяновск, Россия</p>
<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="node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<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">
<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">
<span class="text-muted">${price}</span>
<button class="btn btn-sm btn-outline-primary">
<i class="bi bi-cart-plus"></i> В корзину
<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">
<i class="bi bi-heart"></i>
<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>
<i class="bi bi-share"></i> Поделиться
</button>
</div>
</div>
</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

@@ -1,95 +1,162 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>cyxaruk shop contacts</title>
<meta charset="utf-8" />
<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">
<link href="css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="css/styles.css" />
<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>
<div class="content">
<header class="header">
<a href="main.html" class="logo">
<img src="img/cyxaruk shop logo.jpg" alt="сухарик шоп" />
<h1>cyxaruk shop</h1>
</a>
<ul class="menu">
<li class="dropdown">
<a href="catalog.html">Catalog ▾</a>
<ul class="features-menu">
<li><a href="#">For Men</a></li>
<li><a href="#">For Women</a></li>
<li><a href="#">For Kids</a></li>
<li><a href="#">Order from abroad</a></li>
</ul>
</li>
<li><a href="contacts.html">Contacts</a></li>
<li><a href="likes.html">Likes</a></li>
<li><a href="basket.html">
<img src="img/basket.png" width="50" height="50" alt="корзина" />
</a></li>
</ul>
</header>
<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="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="main">
<div class="table-wrapper">
<table>
<caption>Контакты (звонить только в поддержку)</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>
<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="footer">
<div class="social-container">
<div class="social">
<a href="https://t.me/cyxarukShop">
<img src="img/telega.png" width="100" height="100" alt="Telegram" />
</a>
<h2>← also follow us on tg</h2>
<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>
<div class="social">
<a href="https://www.avito.ru/brands/6f43f8798e9eb61c3350f391762e98b3/all/odezhda_obuv_aksessuary">
<img src="img/avito.png" width="80" height="80" alt="Avito" />
</a>
<h1>← and avito</h1>
</div>
</div>
<div class="contact-info">
<h2>89876320523</h2>
<h2>Ulyanovsk, Russia</h2>
</div>
</footer>
</div>
<script src="js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -1,35 +0,0 @@
/* Кастомные цвета */
.bg-primary {
background-color: #112d4e !important;
}
/* Отступ для фиксированной навигации */
body {
padding-top: 56px;
}
/* Кастомные карточки */
.card {
transition: transform 0.2s;
}
.card:hover {
transform: translateY(-5px);
}
/* Адаптация изображений */
.card-img-top {
height: 200px;
object-fit: cover;
}
/* Кастомные кнопки */
.btn-outline-primary {
--bs-btn-hover-bg: #112d4e;
}
/* Адаптация для мобильных */
@media (max-width: 768px) {
.navbar-brand h1 {
font-size: 1rem;
}
}

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

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

File diff suppressed because one or more lines are too long

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

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

View File

@@ -1 +0,0 @@
.bg-primary{background-color:#112d4e!important}body{padding-top:56px}.card{transition:transform .2s}.card:hover{transform:translateY(-5px)}.card-img-top{height:200px;object-fit:cover}.btn-outline-primary{--bs-btn-hover-bg: #112d4e}@media (max-width: 768px){.navbar-brand h1{font-size:1rem}}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

164
dist/basket.html vendored
View File

@@ -2,61 +2,123 @@
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<title>cyxaruk shop catalog</title>
<link rel="shortcut icon" href="/assets/favicon-cXvr3Sfo.ico" type="image/x-icon">
<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">
<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">
<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>
</head>
<body>
<div class="header">
<a href="main.html" class="logo">
<img src="/assets/cyxaruk%20shop%20logo-DRloma41.jpg" alt="сухарик шоп">
<h1>cyxaruk shop</h1>
</a>
<ul class="menu">
<li class="dropdown">
<a href="catalog.html">Catalog ▾</a>
<ul class="features-menu">
<li><a href="#">For Men</a></li>
<li><a href="#">For Women</a></li>
<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>
<li><a href="#">Order from abroad</a></li>
</ul>
</li>
<li><a href="contacts.html">Contacts</a></li>
<li><a href="likes.html">Likes</a></li>
<li><a href="basket.html">
<img src="/assets/basket-CMXx_bEF.png" width="50" height="50" alt="корзина">
</a></li>
</ul>
</div>
<div class="sad">
<h1>Здесь будут лежать твои товары, <br/> а пока здесь так пусто...</h1>
<img src="/assets/sad1-DBuXZxMU.jpg">
</div>
<div class="footer">
<div class="social-container">
<div class="social">
<a href="https://t.me/cyxarukShop">
<img src="/assets/telega-CVjeM3Sj.png" width="100" height="100" alt="Telegram">
</a>
<h2>← also follow us on tg</h2>
</div>
<div class="social">
<a href="https://www.avito.ru/brands/6f43f8798e9eb61c3350f391762e98b3/all/odezhda_obuv_aksessuary?gdlkerfdnwq=101&page_from=from_item_card&iid=3935618105&sellerId=81d843720716be16ce230bba484bce75">
<img src="/assets/avito-CsvEEyyf.png" width="80" height="80" alt="Avito">
</ul>
</div>
</div>
</div>
<div class="contact-info">
</div>
</nav>
<main class="container my-4">
<div class="empty-basket text-center py-5">
<h1 class="mb-4">Здесь будут лежать твои товары</h1>
<p class="lead mb-4">А пока здесь так пусто...</p>
<img src="/assets/sad1-DBuXZxMU.jpg" 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-arrow-left me-2"></i>Вернуться в каталог
</a>
</div>
<h2>Ulyanovsk, Russia</h2>
</div>
</div>
<div id="basketContainer"></div>
</main>
<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 src="js/bootstrap.bundle.min.js"></script>

410
dist/catalog.html vendored
View File

@@ -2,22 +2,42 @@
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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 -->
<!-- Bootstrap Icons -->
<!-- Минимальные кастомные стили -->
<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">
<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>
<link rel="stylesheet" crossorigin href="/assets/styles-hlLHg5xD.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #00264d;">
<div class="container">
<nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top">
<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">
@@ -25,170 +45,384 @@
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<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 class="nav-link dropdown-toggle" href="catalog.html" role="button" data-bs-toggle="dropdown">
Каталог
</a>
<ul class="dropdown-menu">
</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><a class="dropdown-item" href="#">Для женщин</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>
</ul>
<li class="nav-item">
<a class="nav-link" href="contacts.html"><i class="bi bi-telephone me-1"></i>Контакты</a>
</li>
<a class="nav-link" href="contacts.html">Контакты</a>
</li>
<li class="nav-item">
<li class="nav-item">
<a class="nav-link" href="likes.html"><i class="bi bi-heart me-1"></i>Избранное</a>
</li>
</a>
</li>
<li class="nav-item">
<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>
</div>
</nav>
<main class="container mt-5 pt-4">
<!-- Форма для добавления товаров -->
<div class="card mb-4">
<div class="card-body">
<h2 class="card-title">Добавить новый товар</h2>
<form id="addProductForm" class="row g-3">
<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="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>
<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-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 btn-primary">
<i class="bi bi-plus-circle"></i> Добавить товар
</div>
</div>
</div>
</div>
<h1 class="text-center mb-4 mt-2">Каталог товаров</h1>
</div>
<!-- Карточки товаров -->
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-5" id="productsContainer">
<!-- Карточка товара 1 -->
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4" id="productsContainer">
<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 h-100">
<img src="/assets/stonik-D_cwcHTM.jpg" class="card-img-top" alt="Stone Island">
<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">
<div class="d-flex justify-content-between align-items-center">
<div class="card-footer bg-transparent">
<div class="d-flex justify-content-between align-items-center">
<span class="text-muted">$1999.99</span>
<button class="btn btn-sm" style="background-color: #00264d; color: white;">
<i class="bi bi-cart-plus me-1"></i>В корзину
</button>
</div>
</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>
<i class="bi bi-heart"></i>
<button class="btn btn-sm btn-outline-secondary">
<i class="bi bi-share"></i> Поделиться
</button>
</div>
</div>
</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>
</div>
</main>
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
<div class="container">
<footer class="bg-dark text-white py-4 mt-5">
<div class="row">
<div class="col-md-6 mb-3 mb-md-0">
<div class="d-flex align-items-center mb-3">
<div class="col-md-6">
<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">
</div>
<a href="https://www.avito.ru/..." class="text-white me-3">
<i class="bi bi-shop-window fs-2"></i>
</a>
<span>Мы на Авито</span>
</div>
<span>Мы на Авито</span>
</div>
<div class="col-md-6 text-md-end">
</div>
<div class="col-md-6 text-md-end mt-3 mt-md-0">
<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>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<!-- Bootstrap JS -->
<script>
document.getElementById("addProductForm").addEventListener("submit", function (e) {
<script>
document.getElementById('addProductForm').addEventListener('submit', function(e) {
e.preventDefault();
const name = document.getElementById('productName').value;
const price = document.getElementById('productPrice').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="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">
<div class="card-footer bg-transparent">
<div class="d-flex justify-content-between align-items-center">
<span class="text-muted">${price}</span>
<button class="btn btn-sm" style="background-color: #00264d; color: white;">
<i class="bi bi-cart-plus me-1"></i>В корзину
</button>
</div>
</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>
<i class="bi bi-heart"></i>
<button class="btn btn-sm btn-outline-secondary">
<i class="bi bi-share"></i> Поделиться
</button>
</div>
</div>
</div>
</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>

257
dist/contacts.html vendored
View File

@@ -1,95 +1,162 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>cyxaruk shop contacts</title>
<link rel="shortcut icon" href="/assets/favicon-cXvr3Sfo.ico" type="image/x-icon">
<link rel="stylesheet" crossorigin href="/assets/bootstrap-CvKP2mzs.css">
<link rel="stylesheet" crossorigin href="/assets/styles-hlLHg5xD.css">
</head>
<body>
<div class="content">
<header class="header">
<a href="main.html" class="logo">
<img src="/assets/cyxaruk%20shop%20logo-DRloma41.jpg" alt="сухарик шоп" />
<h1>cyxaruk shop</h1>
</a>
<ul class="menu">
<li class="dropdown">
<a href="catalog.html">Catalog ▾</a>
<ul class="features-menu">
<li><a href="#">For Men</a></li>
<li><a href="#">For Women</a></li>
<li><a href="#">For Kids</a></li>
<li><a href="#">Order from abroad</a></li>
</ul>
</li>
<li><a href="contacts.html">Contacts</a></li>
<li><a href="likes.html">Likes</a></li>
<li><a href="basket.html">
<img src="/assets/basket-CMXx_bEF.png" width="50" height="50" alt="корзина" />
</a></li>
</ul>
</header>
<main class="main">
<div class="table-wrapper">
<table>
<caption>Контакты (звонить только в поддержку)</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>
</main>
<footer class="footer">
<div class="social-container">
<div class="social">
<a href="https://t.me/cyxarukShop">
<img src="/assets/telega-CVjeM3Sj.png" width="100" height="100" alt="Telegram" />
</a>
<h2>← also follow us on tg</h2>
</div>
<div class="social">
<a href="https://www.avito.ru/brands/6f43f8798e9eb61c3350f391762e98b3/all/odezhda_obuv_aksessuary">
<img src="/assets/avito-CsvEEyyf.png" width="80" height="80" alt="Avito" />
</a>
<h1>← and avito</h1>
</div>
</div>
<div class="contact-info">
<h2>89876320523</h2>
<h2>Ulyanovsk, Russia</h2>
</div>
</footer>
</div>
<script src="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>

174
dist/likes.html vendored
View File

@@ -1,66 +1,108 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>cyxaruk shop catalog</title>
<link rel="shortcut icon" href="/assets/favicon-cXvr3Sfo.ico" type="image/x-icon">
<link rel="stylesheet" crossorigin href="/assets/bootstrap-CvKP2mzs.css">
<link rel="stylesheet" crossorigin href="/assets/styles-hlLHg5xD.css">
</head>
<body>
<div class="content">
<div class="header">
<a href="main.html" class="logo">
<img src="/assets/cyxaruk%20shop%20logo-DRloma41.jpg" alt="сухарик шоп">
<h1>cyxaruk shop</h1>
</a>
<ul class="menu">
<li class="dropdown">
<a href="catalog.html">Catalog ▾</a>
<ul class="features-menu">
<li><a href="#">For Men</a></li>
<li><a href="#">For Women</a></li>
<li><a href="#">For Kids</a></li>
<li><a href="#">Order from abroad</a></li>
</ul>
</li>
<li><a href="contacts.html">Contacts</a></li>
<li><a href="likes.html">User</a></li>
<li><a href="basket.html">
<img src="/assets/basket-CMXx_bEF.png" width="50" height="50" alt="корзина">
</a></li>
</ul>
</div>
<div class="sad">
<h1>Здесь будут лежать товары, которые тебе понравились, <br/> а пока здесь так пусто...</h1>
<img src="/assets/sad2-GwJVM7cz.jpeg" width="500" height="300">
</div>
<div class="footer">
<div class="social-container">
<div class="social">
<a href="https://t.me/cyxarukShop">
<img src="/assets/telega-CVjeM3Sj.png" width="100" height="100" alt="Telegram">
</a>
<h2>← also follow us on tg</h2>
</div>
<div class="social">
<a href="https://www.avito.ru/brands/6f43f8798e9eb61c3350f391762e98b3/all/odezhda_obuv_aksessuary?gdlkerfdnwq=101&page_from=from_item_card&iid=3935618105&sellerId=81d843720716be16ce230bba484bce75">
<img src="/assets/avito-CsvEEyyf.png" width="80" height="80" alt="Avito">
</a>
<h1>← and avito</h1>
</div>
</div>
<div class="contact-info">
<h2>89876320523</h2>
<h2>Ulyanovsk, Russia</h2>
</div>
</div>
</div>
<script src="js/bootstrap.bundle.min.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<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">
<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">
<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>
<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">
<div class="text-center py-5 empty-likes">
<h1 class="mb-4">Здесь будут лежать товары, которые тебе понравились</h1>
<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;">
<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;">
<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>

302
dist/main.html vendored
View File

@@ -1,130 +1,174 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="/assets/favicon-cXvr3Sfo.ico" type="image/x-icon">
<title>cyxaruk shop</title>
<link rel="stylesheet" crossorigin href="/assets/bootstrap-CvKP2mzs.css">
<link rel="stylesheet" crossorigin href="/assets/styles-hlLHg5xD.css">
</head>
<body>
<div class="content">
<div class="header">
<a href="main.html" class="logo">
<img src="/assets/cyxaruk%20shop%20logo-DRloma41.jpg" alt="сухарик шоп">
<h1>cyxaruk shop</h1>
</a>
<ul class="menu">
<li class="dropdown">
<a href="catalog.html">Catalog ▾</a>
<ul class="features-menu">
<li><a href="#">For Men</a></li>
<li><a href="#">For Women</a></li>
<li><a href="#">For Kids</a></li>
<li><a href="#">Order from abroad</a></li>
</ul>
</li>
<li><a href="contacts.html">Contacts</a></li>
<li><a href="likes.html">Likes</a></li>
<li><a href="basket.html">
<img src="/assets/basket-CMXx_bEF.png" width="50" height="50" alt="корзина">
</a></li>
</ul>
</div>
<main class="main">
<div class="promo-section">
<div class="image-container">
<img src="/assets/%D1%88%D0%BC%D0%BE%D1%82%D0%BA%D0%B82-CnCqIiH2.jpg" alt="Шмотки">
</div>
<div class="text-container">
<h2> <em>Official cyxaruk shop website</em> </h2>
<a href="catalog.html" class="button"> Go shopping </a>
</div>
</div>
<div class="text-container">
<h1>ONLY THE FATTEST STUFF</h1>
</div>
<div class="page">
<img src="/assets/%D1%88%D0%BC%D0%BE%D1%82%D0%BA%D0%B8-mMMCdlPj.jpg" alt="шмотки1">
<img src="/assets/%D1%88%D0%BC%D0%BE%D1%82%D0%BA%D0%B831-TxMfC034.jpg" alt="шмотки2">
</div>
<h1><em>Отзывы</em></h1>
<div class="feedback">
<div class="column">
<div class="avatar"></div>
<h3 class="username">Pistoletov Sasha</h3>
<p class="comment">
стон 1200 рублей и расход, го можно пж?
</p>
</div>
<div class="column">
<div class="avatar"></div>
<h3 class="username">AUC EVGEN</h3>
<p class="comment">
Сотрудничаем уже 7 лет, все четко
</p>
</div>
<div class="column">
<div class="avatar"></div>
<h3 class="username">Vupava Kitalya</h3>
<p class="comment">
Просил найти его бренд Napapisaj, очень редкая штука, но он справился, 10/10
</p>
</div>
<div class="column">
<div class="avatar"></div>
<h3 class="username">Anjela Danil</h3>
<p class="comment">
Норм продавец, 9/10, пук пук
</p>
</div>
<div class="column">
<div class="avatar"></div>
<h3 class="username">Hater228</h3>
<p class="comment">
Как от ****** отойдешь, цену поменяй, клоун
</p>
</div>
<div class="column">
<div class="avatar"></div>
<h3 class="username">Bima Daryshev</h3>
<p class="comment">
При покупке не возникло никаких проблем, предоставляет огромное кол-во скидок
</p>
</div>
</div>
</main>
<div class="footer">
<div class="social-container">
<div class="social">
<a href="https://t.me/cyxarukShop">
<img src="/assets/telega-CVjeM3Sj.png" width="100" height="100" alt="Telegram">
</a>
<h2>← also follow us on tg</h2>
</div>
<div class="social">
<a href="https://www.avito.ru/brands/...">
<img src="/assets/avito-CsvEEyyf.png" width="80" height="80" alt="Avito">
</a>
<h1>← and avito</h1>
</div>
</div>
<div class="contact-info">
<h2>89876320523</h2>
<h2>Ulyanovsk, Russia</h2>
</div>
</div>
</div>
<script src="js/bootstrap.bundle.min.js"></script>
</body>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<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">
<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">
<style>
body {
color: #00264d;
}
</style>
<link rel="stylesheet" crossorigin href="/assets/styles-cpwRBDRQ.css">
</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">
<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 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>Начать покупки
</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">
<img src="/assets/%D1%88%D0%BC%D0%BE%D1%82%D0%BA%D0%B8-mMMCdlPj.jpg" alt="Товары 1" class="img-fluid rounded shadow">
</div>
<div class="col-md-6">
<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="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="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>
</main>
<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>
</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

File diff suppressed because one or more lines are too long

View File

@@ -2,63 +2,117 @@
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>cyxaruk shop catalog</title>
<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">
<link href="css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="css/styles.css" />
<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="./styles.css" />
</head>
<body>
<div class="content">
<div class="header">
<a href="main.html" class="logo">
<img src="img/cyxaruk shop logo.jpg" alt="сухарик шоп">
<h1>cyxaruk shop</h1>
<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="img/cyxaruk shop logo.jpg" alt="логотип" width="50" height="50" class="rounded-circle me-2">
<span class="fw-bold">cyxaruk shop</span>
</a>
<ul class="menu">
<li class="dropdown">
<a href="catalog.html">Catalog ▾</a>
<ul class="features-menu">
<li><a href="#">For Men</a></li>
<li><a href="#">For Women</a></li>
<li><a href="#">For Kids</a></li>
<li><a href="#">Order from abroad</a></li>
</ul>
</li>
<li><a href="contacts.html">Contacts</a></li>
<li><a href="likes.html">User</a></li>
<li><a href="basket.html">
<img src="img/basket.png" width="50" height="50" alt="корзина">
</a></li>
</ul>
</div>
<div class="sad">
<h1>Здесь будут лежать товары, которые тебе понравились, <br/> а пока здесь так пусто...</h1>
<img src="img/sad2.jpeg" width="500" height="300">
</div>
<div class="footer">
<div class="social-container">
<div class="social">
<a href="https://t.me/cyxarukShop">
<img src="img/telega.png" width="100" height="100" alt="Telegram">
</a>
<h2>← also follow us on tg</h2>
</div>
<div class="social">
<a href="https://www.avito.ru/brands/6f43f8798e9eb61c3350f391762e98b3/all/odezhda_obuv_aksessuary?gdlkerfdnwq=101&page_from=from_item_card&iid=3935618105&sellerId=81d843720716be16ce230bba484bce75">
<img src="img/avito.png" width="80" height="80" alt="Avito">
</a>
<h1>← and avito</h1>
</div>
</div>
<div class="contact-info">
<h2>89876320523</h2>
<h2>Ulyanovsk, Russia</h2>
<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>
</div>
<script src="js/bootstrap.bundle.min.js"></script>
</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 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;">
<div class="mt-4">
<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;">
<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 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>
</html>

256
main.html
View File

@@ -2,127 +2,173 @@
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
<link href="css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="css/styles.css" />
<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">
<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="./styles.css" />
<style>
body {
color: #00264d;
}
</style>
</head>
<body>
<div class="content">
<div class="header">
<a href="main.html" class="logo">
<img src="img/cyxaruk shop logo.jpg" alt="сухарик шоп">
<h1>cyxaruk shop</h1>
<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="img/cyxaruk shop logo.jpg" alt="логотип" width="50" height="50" class="rounded-circle me-2">
<span class="fw-bold">cyxaruk shop</span>
</a>
<ul class="menu">
<li class="dropdown">
<a href="catalog.html">Catalog ▾</a>
<ul class="features-menu">
<li><a href="#">For Men</a></li>
<li><a href="#">For Women</a></li>
<li><a href="#">For Kids</a></li>
<li><a href="#">Order from abroad</a></li>
</ul>
</li>
<li><a href="contacts.html">Contacts</a></li>
<li><a href="likes.html">Likes</a></li>
<li><a href="basket.html">
<img src="img/basket.png" width="50" height="50" alt="корзина">
</a></li>
</ul>
<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="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-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>Начать покупки
</a>
</div>
</div>
<main class="main">
<div class="promo-section">
<div class="image-container">
<img src="img/шмотки2.jpg" alt="Шмотки">
</div>
<div class="text-container">
<h2> <em>Official cyxaruk shop website</em> </h2>
<a href="catalog.html" class="button"> Go shopping </a>
<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">
</div>
<div class="col-md-6">
<img src="img/шмотки31.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="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="AUC EVGEN">
<h5 class="card-title">AUC EVGEN</h5>
<p class="card-text">Сотрудничаем уже 7 лет, все четко</p>
</div>
</div>
</div>
<div class="text-container">
<h1>ONLY THE FATTEST STUFF</h1>
</div>
<div class="page">
<img src="img/шмотки.jpg" alt="шмотки1">
<img src="img/шмотки31.jpg" alt="шмотки2">
<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>
<h1><em>Отзывы</em></h1>
<div class="feedback">
<div class="column">
<div class="avatar"></div>
<h3 class="username">Pistoletov Sasha</h3>
<p class="comment">
стон 1200 рублей и расход, го можно пж?
</p>
</div>
<div class="column">
<div class="avatar"></div>
<h3 class="username">AUC EVGEN</h3>
<p class="comment">
Сотрудничаем уже 7 лет, все четко
</p>
</div>
<div class="column">
<div class="avatar"></div>
<h3 class="username">Vupava Kitalya</h3>
<p class="comment">
Просил найти его бренд Napapisaj, очень редкая штука, но он справился, 10/10
</p>
</div>
<div class="column">
<div class="avatar"></div>
<h3 class="username">Anjela Danil</h3>
<p class="comment">
Норм продавец, 9/10, пук пук
</p>
</div>
<div class="column">
<div class="avatar"></div>
<h3 class="username">Hater228</h3>
<p class="comment">
Как от ****** отойдешь, цену поменяй, клоун
</p>
</div>
<div class="column">
<div class="avatar"></div>
<h3 class="username">Bima Daryshev</h3>
<p class="comment">
При покупке не возникло никаких проблем, предоставляет огромное кол-во скидок
</p>
<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>
</main>
<div class="footer">
<div class="social-container">
<div class="social">
<a href="https://t.me/cyxarukShop">
<img src="img/telega.png" width="100" height="100" alt="Telegram">
</a>
<h2>← also follow us on tg</h2>
</div>
<div class="social">
<a href="https://www.avito.ru/brands/...">
<img src="img/avito.png" width="80" height="80" alt="Avito">
</a>
<h1>← and avito</h1>
<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="contact-info">
<h2>89876320523</h2>
<h2>Ulyanovsk, Russia</h2>
<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>
</div>
<script src="js/bootstrap.bundle.min.js"></script>
</div>
</main>
<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>
</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":"AACA,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,UAAU,MAAM,YAAY,CAAA;AAEnC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;AAE1F,MAAM,SAAS,GAAG,CAAC,IAAa,EAAW,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAA;AAEtE,MAAM,OAAO,OAAO;IAGlB,YAAY,GAAuB;QACjC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAA;QAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAA;IACvC,CAAC;IACD;;;;OAIG;IACH,KAAK,CAAC,KAAwB,EAAE,GAAG,IAAc;QAC/C,IAAI,SAAS,GAAa,EAAE,CAAA;QAE5B,8BAA8B;QAC9B,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,SAAS,GAAG,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAA;QAC9B,CAAC;aAAM,IAAI,KAAK,EAAE,CAAC;YACjB,SAAS,GAAG,CAAC,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,CAAA;QACjC,CAAC;QAED,uCAAuC;QACvC,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAA;QACrC,CAAC;QAED,4CAA4C;QAC5C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACzB,OAAO,SAAS,CAAC,CAAC,CAAC,CAAA;QACrB,CAAC;QAED,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAa,CAAC,CAAA;QAC/E,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAA;QAEvB,OAAO,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IACxD,CAAC;IACD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IACD;;;;;;;OAOG;IACH,SAAS,CAAC,SAA4B,EAAE,GAAG,IAAc;QACvD,IAAI,UAAU,GAAa,SAAqB,CAAA;QAEhD,8BAA8B;QAC9B,IAAI,UAAU,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7C,UAAU,GAAG,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAAA;QACpC,CAAC;QAED,+CAA+C;QAC/C,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAA;QACpC,CAAC;QAED,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAA;IAC1D,CAAC;IACD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;IACD;;;;;;;OAOG;IACH,QAAQ,CAAC,QAA4B,EAAE,GAAG,IAAc;QACtD,IAAI,SAAS,GAAa,QAAoB,CAAA;QAE9C,8BAA8B;QAC9B,IAAI,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3C,SAAS,GAAG,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAA;QAClC,CAAC;QAED,6CAA6C;QAC7C,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAA;QACnC,CAAC;QAED,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAA;IACxD,CAAC;IACD,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;IACD;;;;;;;;OAQG;IACH,SAAS,CAAC,SAA4B,EAAE,GAAG,IAAc;QACvD,IAAI,UAAU,GAAa,SAAqB,CAAA;QAEhD,8BAA8B;QAC9B,IAAI,UAAU,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7C,UAAU,GAAG,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAAA;QACpC,CAAC;QAED,+CAA+C;QAC/C,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAA;QACpC,CAAC;QAED,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAA;IAC1D,CAAC;IACD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;IACD,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;IACD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;CACF"}

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":";;;;;;AAEA,MAAqB,IAAI;IAKvB,YAAY,GAAG,IAAe;QAJ9B,gCAAmB,IAAI,GAAG,EAAkB,EAAC;QAC7C,gCAAmB,IAAI,GAAG,EAAkB,EAAC;QAC7C,iCAAoB,IAAI,GAAG,EAAuB,EAAC;QAGjD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAcD,MAAM,CAAC,OAAgB,EAAE,KAAK,GAAG,KAAK;QACpC,KAAK,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAEvD,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAC1B,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;YAExD,IAAI,CAAC,uBAAA,IAAI,8BAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtC,uBAAA,IAAI,8BAAkB,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,EAAU,CAAC,CAAC;YACtD,CAAC;YACD,MAAM,aAAa,GAAG,uBAAA,IAAI,8BAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAEvD,IAAI,KAAK,GAAG,IAAI,CAAC;YACjB,KAAK,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;gBACjC,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;gBAE1C,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAGrD,aAAa,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;gBAE9B,IAAI,KAAK,EAAE,CAAC;oBAEV,uBAAA,IAAI,6BAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBAC7C,CAAC;gBACD,KAAK,GAAG,KAAK,CAAC;gBAGd,IAAI,OAAO;oBAAE,SAAS;gBAGtB,MAAM,WAAW,GAAG,uBAAA,IAAI,6BAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACzD,IAAI,WAAW,IAAI,WAAW,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBACjD,MAAM,IAAI,KAAK,CACb,IAAI,IAAI,OAAO,SAAS,qBAAqB,WAAW,OAAO,SAAS,qDAAqD,CAC9H,CAAC;gBACJ,CAAC;gBACD,uBAAA,IAAI,6BAAiB,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAKD,OAAO,CAAC,IAAY;QAClB,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAG1C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAGxD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAEpD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAG5C,IAAI,CAAC,MAAM,IAAI,OAAO;YAAE,OAAO,IAAI,CAAC;QAEpC,OAAO,uBAAA,IAAI,6BAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IAChD,CAAC;IAKD,YAAY,CAAC,IAAY;QACvB,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAG1C,IAAI,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7B,OAAO,CACL,CAAC,IAAI,IAAI,uBAAA,IAAI,6BAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,IAAI,CACvE,CAAC;IACJ,CAAC;IAKD,gBAAgB,CAAC,IAAY;QAC3B,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAE1C,OAAO,uBAAA,IAAI,8BAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;IAChE,CAAC;IAMD,OAAO;QACL,IAAI,CAAC,MAAM,GAAG,GAAG,EAAE;YACjB,MAAM,IAAI,KAAK,CAAC,8HAA8H,CAAC,CAAC;QAClJ,CAAC,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEpB,KAAK,MAAM,UAAU,IAAI,uBAAA,IAAI,8BAAkB,CAAC,MAAM,EAAE,EAAE,CAAC;YACzD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,aAAa;QACX,OAAO;YACL,KAAK,EAAE,uBAAA,IAAI,6BAAiB;YAC5B,UAAU,EAAE,uBAAA,IAAI,6BAAiB;SAClC,CAAC;IACJ,CAAC;CACF;;eAtIoB,IAAI"}

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":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,WAAW,CAAA;AAErD,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAC1F,OAAO,EAAE,MAAM,EAAkB,MAAM,kBAAkB,CAAA;AAGzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAGhD,OAAO,KAAK,EAAE,OAAO,EAAa,MAAM,cAAc,CAAA;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAyB7G;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,qBAAa,GAAG,CAAC,GAAG,SAAS,OAAO,GAAG,OAAO,EAAE,GAAG,SAAS,QAAQ,GAAG,QAAQ,CAC7E,SAAQ,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAC5B,YAAW,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC;;IAEjC,UAAU,EAAE,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAK;IACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAK;IACpC,cAAc,EAAE,OAAO,CAAA;IACvB,OAAO,EAAE,YAAY,CAAA;IACrB,QAAQ,EAAE,WAAW,CAAA;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAK;IAC5C,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IACzD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;gBAElB,OAAO,GAAE,cAAc,CAAC,GAAG,EAAE,GAAG,CAAM;IAmBlD,GAAG,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI;IAMzE,MAAM,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI;IAMrD,OAAO,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,OAAO,EAAE,CAAC;IAI/C,OAAO,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI;IAMtD,IAAI;IAIJ,MAAM,CAAC,aAAa,SAAS,qBAAqB,GAAG,qBAAqB,EACxE,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,cAAc,CAAC,aAAa,CAAC,GAChC,IAAI;IAKP,MAAM,CAAC,aAAa,SAAS,qBAAqB,GAAG,qBAAqB,EACxE,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAClC,OAAO,GAAE,gBAAgB,CAAC,aAAa,CAAyC,EAChF,EAAE,GAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAe;IA0CvD,GAAG,CAAC,GAAG,IAAI,EAAE,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI;IAmErE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC;IAsBlC,OAAO,CAAC,aAAa,SAAS,qBAAqB,GAAG,qBAAqB,EACzE,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,GAAG,EACR,IAAI,CAAC,EAAE,YAAY;IAmHrB,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM;CAGrD"}

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

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