diff --git a/ init_db.php b/ init_db.php
deleted file mode 100644
index 901a438..0000000
--- a/ init_db.php
+++ /dev/null
@@ -1,122 +0,0 @@
-getConnection();
-
-// Создаем таблицы, если они не существуют
-$tables = [
- 'users' => "
- CREATE TABLE IF NOT EXISTS users (
- user_id SERIAL PRIMARY KEY,
- email VARCHAR(255) UNIQUE NOT NULL,
- password_hash VARCHAR(255) NOT NULL,
- full_name VARCHAR(100) NOT NULL,
- phone VARCHAR(20),
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- is_active BOOLEAN DEFAULT TRUE,
- is_admin BOOLEAN DEFAULT FALSE
- )
- ",
-
- 'categories' => "
- CREATE TABLE IF NOT EXISTS categories (
- category_id SERIAL PRIMARY KEY,
- name VARCHAR(100) NOT NULL,
- slug VARCHAR(100) UNIQUE NOT NULL,
- parent_id INTEGER REFERENCES categories(category_id),
- description TEXT,
- sort_order INTEGER DEFAULT 0,
- is_active BOOLEAN DEFAULT TRUE
- )
- ",
-
- 'products' => "
- CREATE TABLE IF NOT EXISTS products (
- product_id SERIAL PRIMARY KEY,
- category_id INTEGER REFERENCES categories(category_id),
- name VARCHAR(200) NOT NULL,
- slug VARCHAR(200) UNIQUE NOT NULL,
- description TEXT,
- price DECIMAL(10, 2) NOT NULL,
- old_price DECIMAL(10, 2),
- sku VARCHAR(50) UNIQUE,
- stock_quantity INTEGER DEFAULT 0,
- is_available BOOLEAN DEFAULT TRUE,
- is_featured BOOLEAN DEFAULT FALSE,
- rating DECIMAL(3, 2) DEFAULT 0,
- review_count INTEGER DEFAULT 0,
- image_url VARCHAR(500),
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- )
- "
-];
-
-foreach ($tables_to_create as $table_name => $sql) {
- try {
- $db->exec($sql);
- echo "Таблица '$table_name' создана/проверена ";
- } catch (PDOException $e) {
- echo "Ошибка создания таблицы '$table_name': " . $e->getMessage() . " ";
- }
-}
-
-// Добавляем тестовые данные
-// Проверяем, есть ли уже категории
-$check_categories = $db->query("SELECT COUNT(*) FROM categories")->fetchColumn();
-
-if ($check_categories == 0) {
- // Добавляем категории
- $categories = [
- ['Мягкая мебель', 'myagkaya-mebel', NULL, 'Диваны, кресла, пуфы'],
- ['Диваны', 'divany', 1, 'Прямые и угловые диваны'],
- ['Кресла', 'kresla', 1, 'Кресла для гостиной и офиса'],
- ['Спальня', 'spalnya', NULL, 'Кровати, тумбы, комоды'],
- ['Кровати', 'krovati', 4, 'Односпальные и двуспальные кровати']
- ];
-
- foreach ($categories as $category) {
- $stmt = $db->prepare("INSERT INTO categories (name, slug, parent_id, description) VALUES (?, ?, ?, ?)");
- $stmt->execute($category);
- }
- echo "Добавлены категории ";
-}
-
-// Проверяем, есть ли уже товары
-$check_products = $db->query("SELECT COUNT(*) FROM products")->fetchColumn();
-
-if ($check_products == 0) {
- // Добавляем товары
- $products = [
- [2, 'Диван VELVET', 'divan-velvet', 'Прямой диван с тканевой обивкой', 45999, 54999, 'DIV-VEL-001', 10],
- [2, 'Диван MODERN', 'divan-modern', 'Угловой диван с кожаной обивкой', 78999, 89999, 'DIV-MOD-002', 5],
- [3, 'Кресло OPPORTUNITY', 'kreslo-opportunity', 'Кресло с деревянными ножками', 16999, 19999, 'KRES-OPP-001', 15],
- [3, 'Кресло GOLDEN', 'kreslo-golden', 'Золотистое кресло для гостиной', 19999, 23999, 'KRES-GOL-002', 8],
- [5, 'Кровать CLASSIC', 'krovat-classic', 'Двуспальная кровать из массива дуба', 64999, 74999, 'KROV-CLA-001', 3]
- ];
-
- foreach ($products as $product) {
- $stmt = $db->prepare("INSERT INTO products (category_id, name, slug, description, price, old_price, sku, stock_quantity)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
- $stmt->execute($product);
- }
- echo "Добавлены товары ";
-}
-
-// Проверяем, есть ли администратор
-$check_admin = $db->prepare("SELECT COUNT(*) FROM users WHERE email = ?");
-$check_admin->execute(['admin@aeterna.ru']);
-
-if ($check_admin->fetchColumn() == 0) {
- // Добавляем администратора (пароль: admin123)
- $admin_password = password_hash('admin123', PASSWORD_DEFAULT);
- $stmt = $db->prepare("INSERT INTO users (email, password_hash, full_name, phone, is_admin)
- VALUES (?, ?, ?, ?, ?)");
- $stmt->execute(['admin@aeterna.ru', $admin_password, 'Администратор AETERNA', '+79129991223', true]);
- echo "Добавлен администратор (email: admin@aeterna.ru, пароль: admin123) ";
-}
-
-echo "
База данных успешно инициализирована! ";
-echo "Перейти в каталог ";
-?>
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..dfbf603
--- /dev/null
+++ b/README.md
@@ -0,0 +1,91 @@
+# AETERNA - Интернет-магазин мебели
+
+## Быстрый старт
+
+```bash
+# 1. Сделать скрипт исполняемым
+chmod +x setup.sh
+
+# 2. Запустить настройку
+./setup.sh
+
+# 3. Или запустить миграции вручную
+php migrations/migrate.php
+php migrations/migrate.php --seed
+```
+
+## Структура проекта
+
+```
+cite_practica1/
+├── public/ # Публичные страницы (точка входа)
+│ ├── index.php # Главная
+│ ├── catalog.php # Каталог
+│ ├── login.php # Вход
+│ ├── register.php # Регистрация
+│ ├── checkout.php # Корзина/оформление заказа
+│ ├── product.php # Страница товара
+│ ├── services.php # Услуги
+│ ├── delivery.php # Доставка и оплата
+│ └── warranty.php # Гарантия
+│
+├── admin/ # Админ-панель
+│ └── index.php # Главная страница админки
+│
+├── api/ # API-эндпоинты (AJAX)
+│ ├── cart.php # Корзина (add/update/remove/get/count)
+│ ├── auth.php # Авторизация
+│ └── ...
+│
+├── config/
+│ └── database.php # Подключение к PostgreSQL
+│
+├── includes/ # Переиспользуемые части
+│ ├── header.php # Единый header
+│ ├── footer.php # Единый footer
+│ ├── functions.php # Общие функции
+│ └── auth.php # Функции авторизации
+│
+├── assets/
+│ ├── css/ # Скомпилированный CSS
+│ ├── less/ # LESS исходники
+│ ├── js/ # JavaScript
+│ └── img/ # Изображения
+│
+├── migrations/ # Миграции БД
+│ ├── migrate.php # Раннер миграций
+│ ├── 001_initial_schema.sql # Базовые таблицы
+│ ├── 002_add_cart_orders.sql# Корзина и заказы
+│ ├── 003_add_product_fields.sql # Доп. поля
+│ └── seed_data.sql # Начальные данные
+│
+└── uploads/ # Загружаемые файлы
+ └── products/
+```
+
+## База данных
+
+**PostgreSQL** с таблицами:
+- `users` - пользователи
+- `categories` - категории товаров
+- `subcategories` - подкатегории
+- `products` - товары
+- `cart` - корзина
+- `orders` - заказы
+- `order_items` - позиции заказа
+
+## Тестовые аккаунты
+
+| Email | Пароль | Роль |
+|-------|--------|------|
+| admin@mail.ru | admin123 | Администратор |
+
+## Миграции
+
+```bash
+# Применить все миграции
+php migrations/migrate.php
+
+# Применить миграции + загрузить тестовые данные
+php migrations/migrate.php --seed
+```
diff --git a/admin_panel.php b/admin/index.php
similarity index 88%
rename from admin_panel.php
rename to admin/index.php
index f8a4252..25d2877 100644
--- a/admin_panel.php
+++ b/admin/index.php
@@ -1,19 +1,15 @@
Сначала добавьте категории!';
-}
-
// Проверка прав администратора
if (!isset($_SESSION['isAdmin']) || $_SESSION['isAdmin'] !== true) {
- echo "";
+ echo "";
exit();
}
@@ -546,7 +542,7 @@ try {
= $action == 'add_category' ? 'Добавление категории' : 'Редактирование категории' ?>
-
-
-
-
-
Заказы
diff --git a/admin_actions.php b/admin_actions.php
deleted file mode 100644
index ea9563b..0000000
--- a/admin_actions.php
+++ /dev/null
@@ -1,170 +0,0 @@
-getConnection();
-$action = $_GET['action'] ?? '';
-
-try {
- switch ($action) {
- case 'delete_product':
- if (isset($_GET['id'])) {
- $productId = intval($_GET['id']);
- // Делаем товар недоступным
- $stmt = $db->prepare("
- UPDATE products
- SET is_available = FALSE, stock_quantity = 0, updated_at = CURRENT_TIMESTAMP
- WHERE product_id = ?
- ");
- $stmt->execute([$productId]);
- header('Location: admin_panel.php?action=products&message=Товар помечен как недоступный');
- exit();
- }
- break;
-
- case 'restore_product':
- if (isset($_GET['id'])) {
- $productId = intval($_GET['id']);
- // Восстанавливаем товар
- $stmt = $db->prepare("
- UPDATE products
- SET is_available = TRUE, stock_quantity = 10, updated_at = CURRENT_TIMESTAMP
- WHERE product_id = ?
- ");
- $stmt->execute([$productId]);
- header('Location: admin_panel.php?action=products&message=Товар восстановлен');
- exit();
- }
- break;
-
- case 'delete_category':
- if (isset($_GET['id'])) {
- $categoryId = intval($_GET['id']);
-
- try {
- // 1. Проверяем, есть ли товары в этой категории
- $checkProducts = $db->prepare("SELECT COUNT(*) FROM products WHERE category_id = ?");
- $checkProducts->execute([$categoryId]);
- $productCount = $checkProducts->fetchColumn();
-
- if ($productCount > 0) {
- // Если есть товары, делаем категорию неактивной
- $stmt = $db->prepare("UPDATE categories SET is_active = FALSE WHERE category_id = ?");
- $stmt->execute([$categoryId]);
- header('Location: admin_panel.php?action=categories&message=Категория скрыта (содержит товары)');
- exit();
- }
-
- // 2. Проверяем, есть ли дочерние категории
- $checkChildren = $db->prepare("SELECT COUNT(*) FROM categories WHERE parent_id = ?");
- $checkChildren->execute([$categoryId]);
- $childCount = $checkChildren->fetchColumn();
-
- if ($childCount > 0) {
- // Вариант A: Делаем категорию неактивной
- $stmt = $db->prepare("UPDATE categories SET is_active = FALSE WHERE category_id = ?");
- $stmt->execute([$categoryId]);
- header('Location: admin_panel.php?action=categories&message=Категория скрыта (имеет дочерние категории)');
- exit();
-
- // Вариант B: Удаляем вместе с дочерними (раскомментируйте если нужно)
- /*
- // Сначала удаляем дочерние категории
- $stmt = $db->prepare("DELETE FROM categories WHERE parent_id = ?");
- $stmt->execute([$categoryId]);
-
- // Затем удаляем саму категорию
- $stmt = $db->prepare("DELETE FROM categories WHERE category_id = ?");
- $stmt->execute([$categoryId]);
-
- header('Location: admin_panel.php?action=categories&message=Категория и её дочерние категории удалены');
- exit();
- */
- }
-
- // 3. Если нет товаров и дочерних категорий, удаляем
- $stmt = $db->prepare("DELETE FROM categories WHERE category_id = ?");
- $stmt->execute([$categoryId]);
-
- header('Location: admin_panel.php?action=categories&message=Категория удалена');
- exit();
-
- } catch (PDOException $e) {
- header('Location: admin_panel.php?action=categories&error=' . urlencode($e->getMessage()));
- exit();
- }
- }
- break;
-
- case 'delete_category_force':
- // Принудительное удаление с дочерними категориями
- if (isset($_GET['id'])) {
- $categoryId = intval($_GET['id']);
-
- try {
- // Сначала перемещаем товары в другую категорию (например, в первую)
- $firstCategory = $db->query("SELECT category_id FROM categories WHERE category_id != ? LIMIT 1")->fetchColumn();
-
- if ($firstCategory) {
- $moveProducts = $db->prepare("UPDATE products SET category_id = ? WHERE category_id = ?");
- $moveProducts->execute([$firstCategory, $categoryId]);
- }
-
- // Обнуляем parent_id у дочерних категорий
- $stmt = $db->prepare("UPDATE categories SET parent_id = NULL WHERE parent_id = ?");
- $stmt->execute([$categoryId]);
-
- // Удаляем категорию
- $stmt = $db->prepare("DELETE FROM categories WHERE category_id = ?");
- $stmt->execute([$categoryId]);
-
- header('Location: admin_panel.php?action=categories&message=Категория удалена. Товары перемещены.');
- exit();
-
- } catch (PDOException $e) {
- header('Location: admin_panel.php?action=categories&error=' . urlencode($e->getMessage()));
- exit();
- }
- }
- break;
-
- case 'toggle_user':
- if (isset($_GET['id'])) {
- $userId = intval($_GET['id']);
- $stmt = $db->prepare("
- UPDATE users
- SET is_active = NOT is_active, updated_at = CURRENT_TIMESTAMP
- WHERE user_id = ?
- ");
- $stmt->execute([$userId]);
- header('Location: admin_panel.php?action=users&message=Статус пользователя изменен');
- exit();
- }
- break;
-
- case 'make_admin':
- if (isset($_GET['id'])) {
- $userId = intval($_GET['id']);
- $stmt = $db->prepare("UPDATE users SET is_admin = TRUE WHERE user_id = ?");
- $stmt->execute([$userId]);
- header('Location: admin_panel.php?action=users&message=Пользователь назначен администратором');
- exit();
- }
- break;
- }
-} catch (PDOException $e) {
- header('Location: admin_panel.php?error=' . urlencode($e->getMessage()));
- exit();
-}
-
-// Если действие не распознано
-header('Location: admin_panel.php');
-exit();
-?>
\ No newline at end of file
diff --git a/add_to_cart.php b/api/add_to_cart.php
similarity index 96%
rename from add_to_cart.php
rename to api/add_to_cart.php
index 4ff29d8..bed64de 100644
--- a/add_to_cart.php
+++ b/api/add_to_cart.php
@@ -1,6 +1,6 @@
false, 'message' => 'Требуется авторизация']);
diff --git a/login_handler.php b/api/auth.php
similarity index 95%
rename from login_handler.php
rename to api/auth.php
index 3f63de6..e37ce6a 100644
--- a/login_handler.php
+++ b/api/auth.php
@@ -1,7 +1,7 @@
false, 'message' => 'Требуется авторизация']);
+ exit();
+}
+
+$userId = $_SESSION['user_id'] ?? 0;
+$action = $_GET['action'] ?? $_POST['action'] ?? '';
+
+$db = Database::getInstance()->getConnection();
+
+try {
+ switch ($action) {
+ case 'add':
+ $productId = (int)($_POST['product_id'] ?? 0);
+ $quantity = (int)($_POST['quantity'] ?? 1);
+
+ if ($productId <= 0) {
+ echo json_encode(['success' => false, 'message' => 'Неверный ID товара']);
+ exit();
+ }
+
+ // Проверяем существование товара
+ $checkProduct = $db->prepare("SELECT product_id, stock_quantity FROM products WHERE product_id = ? AND is_available = TRUE");
+ $checkProduct->execute([$productId]);
+ $product = $checkProduct->fetch();
+
+ if (!$product) {
+ echo json_encode(['success' => false, 'message' => 'Товар не найден']);
+ exit();
+ }
+
+ // Проверяем, есть ли товар уже в корзине
+ $checkCart = $db->prepare("SELECT cart_id, quantity FROM cart WHERE user_id = ? AND product_id = ?");
+ $checkCart->execute([$userId, $productId]);
+ $cartItem = $checkCart->fetch();
+
+ if ($cartItem) {
+ // Обновляем количество
+ $newQuantity = $cartItem['quantity'] + $quantity;
+ $stmt = $db->prepare("UPDATE cart SET quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE cart_id = ?");
+ $stmt->execute([$newQuantity, $cartItem['cart_id']]);
+ } else {
+ // Добавляем новый товар
+ $stmt = $db->prepare("INSERT INTO cart (user_id, product_id, quantity) VALUES (?, ?, ?)");
+ $stmt->execute([$userId, $productId, $quantity]);
+ }
+
+ echo json_encode(['success' => true, 'message' => 'Товар добавлен в корзину']);
+ break;
+
+ case 'update':
+ $productId = (int)($_POST['product_id'] ?? 0);
+ $quantity = (int)($_POST['quantity'] ?? 1);
+
+ if ($quantity <= 0) {
+ // Удаляем товар если количество 0
+ $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ? AND product_id = ?");
+ $stmt->execute([$userId, $productId]);
+ } else {
+ $stmt = $db->prepare("UPDATE cart SET quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE user_id = ? AND product_id = ?");
+ $stmt->execute([$quantity, $userId, $productId]);
+ }
+
+ echo json_encode(['success' => true, 'message' => 'Корзина обновлена']);
+ break;
+
+ case 'remove':
+ $productId = (int)($_POST['product_id'] ?? 0);
+
+ $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ? AND product_id = ?");
+ $stmt->execute([$userId, $productId]);
+
+ echo json_encode(['success' => true, 'message' => 'Товар удален из корзины']);
+ break;
+
+ case 'get':
+ $stmt = $db->prepare("
+ SELECT c.cart_id, c.product_id, c.quantity, p.name, p.price, p.image_url, p.stock_quantity
+ FROM cart c
+ JOIN products p ON c.product_id = p.product_id
+ WHERE c.user_id = ? AND p.is_available = TRUE
+ ORDER BY c.created_at DESC
+ ");
+ $stmt->execute([$userId]);
+ $items = $stmt->fetchAll();
+
+ $total = 0;
+ foreach ($items as &$item) {
+ $item['subtotal'] = $item['price'] * $item['quantity'];
+ $total += $item['subtotal'];
+ }
+
+ echo json_encode([
+ 'success' => true,
+ 'items' => $items,
+ 'total' => $total,
+ 'count' => array_sum(array_column($items, 'quantity'))
+ ]);
+ break;
+
+ case 'count':
+ $stmt = $db->prepare("SELECT COALESCE(SUM(quantity), 0) FROM cart WHERE user_id = ?");
+ $stmt->execute([$userId]);
+ $count = $stmt->fetchColumn();
+
+ echo json_encode(['success' => true, 'count' => (int)$count]);
+ break;
+
+ case 'clear':
+ $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ?");
+ $stmt->execute([$userId]);
+
+ echo json_encode(['success' => true, 'message' => 'Корзина очищена']);
+ break;
+
+ default:
+ echo json_encode(['success' => false, 'message' => 'Неизвестное действие']);
+ }
+
+} catch (PDOException $e) {
+ echo json_encode(['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]);
+}
+
diff --git a/get_cart.php b/api/get_cart.php
similarity index 93%
rename from get_cart.php
rename to api/get_cart.php
index dbef740..c5d2a3c 100644
--- a/get_cart.php
+++ b/api/get_cart.php
@@ -1,7 +1,7 @@
false, 'message' => 'Требуется авторизация']);
diff --git a/get_cart_count.php b/api/get_cart_count.php
similarity index 89%
rename from get_cart_count.php
rename to api/get_cart_count.php
index 39cdc01..eacc4d5 100644
--- a/get_cart_count.php
+++ b/api/get_cart_count.php
@@ -1,7 +1,7 @@
false, 'cart_count' => 0]);
diff --git a/get_product.php b/api/get_product.php
similarity index 91%
rename from get_product.php
rename to api/get_product.php
index e801cd7..e548112 100644
--- a/get_product.php
+++ b/api/get_product.php
@@ -1,6 +1,6 @@
rollBack();
- header('Location: оформление_заказа.php?error=' . urlencode($e->getMessage()));
+ header('Location: checkout.php?error=' . urlencode($e->getMessage()));
exit();
}
} else {
- header('Location: оформление_заказа.php');
+ header('Location: checkout.php');
exit();
}
?>
\ No newline at end of file
diff --git a/register_handler.php b/api/register_handler.php
similarity index 93%
rename from register_handler.php
rename to api/register_handler.php
index 76ce3b9..002dfad 100644
--- a/register_handler.php
+++ b/api/register_handler.php
@@ -1,7 +1,7 @@
$email,
'phone' => $phone
];
- header('Location: профиль.php');
+ header('Location: register.php');
exit();
}
@@ -73,7 +73,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'email' => $email,
'phone' => $phone
];
- header('Location: профиль.php');
+ header('Location: register.php');
exit();
}
@@ -164,19 +164,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'email' => $email,
'phone' => $phone
];
- header('Location: профиль.php');
+ header('Location: register.php');
exit();
} catch (Exception $e) {
error_log("Registration Error: " . $e->getMessage());
$_SESSION['registration_errors'] = [$e->getMessage()];
- header('Location: профиль.php');
+ header('Location: register.php');
exit();
}
} else {
// Если запрос не POST, перенаправляем на форму регистрации
- header('Location: профиль.php');
+ header('Location: register.php');
exit();
}
?>
\ No newline at end of file
diff --git a/update_cart.php b/api/update_cart.php
similarity index 92%
rename from update_cart.php
rename to api/update_cart.php
index 8ab9f4a..0063946 100644
--- a/update_cart.php
+++ b/api/update_cart.php
@@ -1,6 +1,6 @@
false, 'message' => 'Требуется авторизация']);
diff --git a/img2/1 — копия.jpg b/assets/img/1 — копия.jpg
similarity index 100%
rename from img2/1 — копия.jpg
rename to assets/img/1 — копия.jpg
diff --git a/img/1.jpg b/assets/img/1.jpg
similarity index 100%
rename from img/1.jpg
rename to assets/img/1.jpg
diff --git a/img2/100.jpg b/assets/img/100.jpg
similarity index 100%
rename from img2/100.jpg
rename to assets/img/100.jpg
diff --git a/img2/11.jpg b/assets/img/11.jpg
similarity index 100%
rename from img2/11.jpg
rename to assets/img/11.jpg
diff --git a/img2/111.jpg b/assets/img/111.jpg
similarity index 100%
rename from img2/111.jpg
rename to assets/img/111.jpg
diff --git a/img2/11_1.png b/assets/img/11_1.png
similarity index 100%
rename from img2/11_1.png
rename to assets/img/11_1.png
diff --git a/img/1_1.jpg b/assets/img/1_1.jpg
similarity index 100%
rename from img/1_1.jpg
rename to assets/img/1_1.jpg
diff --git a/img2/1_2.jpg b/assets/img/1_2.jpg
similarity index 100%
rename from img2/1_2.jpg
rename to assets/img/1_2.jpg
diff --git a/img2/1_2.png b/assets/img/1_2.png
similarity index 100%
rename from img2/1_2.png
rename to assets/img/1_2.png
diff --git a/img/2.jpg b/assets/img/2.jpg
similarity index 100%
rename from img/2.jpg
rename to assets/img/2.jpg
diff --git a/img2/22.jpg b/assets/img/22.jpg
similarity index 100%
rename from img2/22.jpg
rename to assets/img/22.jpg
diff --git a/img2/25.jpg b/assets/img/25.jpg
similarity index 100%
rename from img2/25.jpg
rename to assets/img/25.jpg
diff --git a/img2/2_2.jpg b/assets/img/2_2.jpg
similarity index 100%
rename from img2/2_2.jpg
rename to assets/img/2_2.jpg
diff --git a/img2/2_2.png b/assets/img/2_2.png
similarity index 100%
rename from img2/2_2.png
rename to assets/img/2_2.png
diff --git a/img2/3.jpg b/assets/img/3.jpg
similarity index 100%
rename from img2/3.jpg
rename to assets/img/3.jpg
diff --git a/img/3_3.jpg b/assets/img/3_3.jpg
similarity index 100%
rename from img/3_3.jpg
rename to assets/img/3_3.jpg
diff --git a/img2/3_3.png b/assets/img/3_3.png
similarity index 100%
rename from img2/3_3.png
rename to assets/img/3_3.png
diff --git a/img2/4.jpg b/assets/img/4.jpg
similarity index 100%
rename from img2/4.jpg
rename to assets/img/4.jpg
diff --git a/img2/44.jpg b/assets/img/44.jpg
similarity index 100%
rename from img2/44.jpg
rename to assets/img/44.jpg
diff --git a/img2/444 b/assets/img/444
similarity index 100%
rename from img2/444
rename to assets/img/444
diff --git a/img2/444 (1).png b/assets/img/444 (1).png
similarity index 100%
rename from img2/444 (1).png
rename to assets/img/444 (1).png
diff --git a/img2/444.jpg b/assets/img/444.jpg
similarity index 100%
rename from img2/444.jpg
rename to assets/img/444.jpg
diff --git a/img2/444.png b/assets/img/444.png
similarity index 100%
rename from img2/444.png
rename to assets/img/444.png
diff --git a/img2/4_1.jpg b/assets/img/4_1.jpg
similarity index 100%
rename from img2/4_1.jpg
rename to assets/img/4_1.jpg
diff --git a/img/5.jpg b/assets/img/5.jpg
similarity index 100%
rename from img/5.jpg
rename to assets/img/5.jpg
diff --git a/img/5_5.jpg b/assets/img/5_5.jpg
similarity index 100%
rename from img/5_5.jpg
rename to assets/img/5_5.jpg
diff --git a/img2/5_5.png b/assets/img/5_5.png
similarity index 100%
rename from img2/5_5.png
rename to assets/img/5_5.png
diff --git a/img2/6.jpg b/assets/img/6.jpg
similarity index 100%
rename from img2/6.jpg
rename to assets/img/6.jpg
diff --git a/img/6_6.jpg b/assets/img/6_6.jpg
similarity index 100%
rename from img/6_6.jpg
rename to assets/img/6_6.jpg
diff --git a/img2/6_6.png b/assets/img/6_6.png
similarity index 100%
rename from img2/6_6.png
rename to assets/img/6_6.png
diff --git a/img2/7.jpg b/assets/img/7.jpg
similarity index 100%
rename from img2/7.jpg
rename to assets/img/7.jpg
diff --git a/img2/77.jpg b/assets/img/77.jpg
similarity index 100%
rename from img2/77.jpg
rename to assets/img/77.jpg
diff --git a/img2/777 (1).png b/assets/img/777 (1).png
similarity index 100%
rename from img2/777 (1).png
rename to assets/img/777 (1).png
diff --git a/img2/777.jpg b/assets/img/777.jpg
similarity index 100%
rename from img2/777.jpg
rename to assets/img/777.jpg
diff --git a/img2/777.png b/assets/img/777.png
similarity index 100%
rename from img2/777.png
rename to assets/img/777.png
diff --git a/img/7_7.jpg b/assets/img/7_7.jpg
similarity index 100%
rename from img/7_7.jpg
rename to assets/img/7_7.jpg
diff --git a/img2/7_7.png b/assets/img/7_7.png
similarity index 100%
rename from img2/7_7.png
rename to assets/img/7_7.png
diff --git a/img2/8.jpg b/assets/img/8.jpg
similarity index 100%
rename from img2/8.jpg
rename to assets/img/8.jpg
diff --git a/img2/88.jpg b/assets/img/88.jpg
similarity index 100%
rename from img2/88.jpg
rename to assets/img/88.jpg
diff --git a/img2/888 (1).png b/assets/img/888 (1).png
similarity index 100%
rename from img2/888 (1).png
rename to assets/img/888 (1).png
diff --git a/img2/888.jpg b/assets/img/888.jpg
similarity index 100%
rename from img2/888.jpg
rename to assets/img/888.jpg
diff --git a/img2/888.png b/assets/img/888.png
similarity index 100%
rename from img2/888.png
rename to assets/img/888.png
diff --git a/img2/8_8.png b/assets/img/8_8.png
similarity index 100%
rename from img2/8_8.png
rename to assets/img/8_8.png
diff --git a/img2/9.jpg b/assets/img/9.jpg
similarity index 100%
rename from img2/9.jpg
rename to assets/img/9.jpg
diff --git a/img2/99.jpg b/assets/img/99.jpg
similarity index 100%
rename from img2/99.jpg
rename to assets/img/99.jpg
diff --git a/img2/99.png b/assets/img/99.png
similarity index 100%
rename from img2/99.png
rename to assets/img/99.png
diff --git a/img2/99_1.jpg b/assets/img/99_1.jpg
similarity index 100%
rename from img2/99_1.jpg
rename to assets/img/99_1.jpg
diff --git a/img2/99_2.jpg b/assets/img/99_2.jpg
similarity index 100%
rename from img2/99_2.jpg
rename to assets/img/99_2.jpg
diff --git a/img2/99_3.png b/assets/img/99_3.png
similarity index 100%
rename from img2/99_3.png
rename to assets/img/99_3.png
diff --git a/img/9_9.jpg b/assets/img/9_9.jpg
similarity index 100%
rename from img/9_9.jpg
rename to assets/img/9_9.jpg
diff --git a/img2/9_9.png b/assets/img/9_9.png
similarity index 100%
rename from img2/9_9.png
rename to assets/img/9_9.png
diff --git a/img2/black.png b/assets/img/black.png
similarity index 100%
rename from img2/black.png
rename to assets/img/black.png
diff --git a/img2/black1.png b/assets/img/black1.png
similarity index 100%
rename from img2/black1.png
rename to assets/img/black1.png
diff --git a/img2/black2.png b/assets/img/black2.png
similarity index 100%
rename from img2/black2.png
rename to assets/img/black2.png
diff --git a/img2/brown.png b/assets/img/brown.png
similarity index 100%
rename from img2/brown.png
rename to assets/img/brown.png
diff --git a/img2/brown1.png b/assets/img/brown1.png
similarity index 100%
rename from img2/brown1.png
rename to assets/img/brown1.png
diff --git a/img2/brown2.png b/assets/img/brown2.png
similarity index 100%
rename from img2/brown2.png
rename to assets/img/brown2.png
diff --git a/img/chair.PNG b/assets/img/chair.PNG
similarity index 100%
rename from img/chair.PNG
rename to assets/img/chair.PNG
diff --git a/img2/gray.png b/assets/img/gray.png
similarity index 100%
rename from img2/gray.png
rename to assets/img/gray.png
diff --git a/img2/gray1.png b/assets/img/gray1.png
similarity index 100%
rename from img2/gray1.png
rename to assets/img/gray1.png
diff --git a/img2/gray2.png b/assets/img/gray2.png
similarity index 100%
rename from img2/gray2.png
rename to assets/img/gray2.png
diff --git a/img/диван.jpg b/assets/img/диван.jpg
similarity index 100%
rename from img/диван.jpg
rename to assets/img/диван.jpg
diff --git a/img/диван_1.jpg b/assets/img/диван_1.jpg
similarity index 100%
rename from img/диван_1.jpg
rename to assets/img/диван_1.jpg
diff --git a/img/кресло.jpg b/assets/img/кресло.jpg
similarity index 100%
rename from img/кресло.jpg
rename to assets/img/кресло.jpg
diff --git a/img/кресло_1.jpg b/assets/img/кресло_1.jpg
similarity index 100%
rename from img/кресло_1.jpg
rename to assets/img/кресло_1.jpg
diff --git a/img/слайдер_1.jpg b/assets/img/слайдер_1.jpg
similarity index 100%
rename from img/слайдер_1.jpg
rename to assets/img/слайдер_1.jpg
diff --git a/img/слайдер_2.jpg b/assets/img/слайдер_2.jpg
similarity index 100%
rename from img/слайдер_2.jpg
rename to assets/img/слайдер_2.jpg
diff --git a/img/слайдер_3.jpg b/assets/img/слайдер_3.jpg
similarity index 100%
rename from img/слайдер_3.jpg
rename to assets/img/слайдер_3.jpg
diff --git a/img/слайдер_4.jpg b/assets/img/слайдер_4.jpg
similarity index 100%
rename from img/слайдер_4.jpg
rename to assets/img/слайдер_4.jpg
diff --git a/img/слайдер_5.jpg b/assets/img/слайдер_5.jpg
similarity index 100%
rename from img/слайдер_5.jpg
rename to assets/img/слайдер_5.jpg
diff --git a/img/слайдер_6.jpg b/assets/img/слайдер_6.jpg
similarity index 100%
rename from img/слайдер_6.jpg
rename to assets/img/слайдер_6.jpg
diff --git a/img/спальня.jpg b/assets/img/спальня.jpg
similarity index 100%
rename from img/спальня.jpg
rename to assets/img/спальня.jpg
diff --git a/img/стили_оформления.css b/assets/img/стили_оформления.css
similarity index 100%
rename from img/стили_оформления.css
rename to assets/img/стили_оформления.css
diff --git a/оформление_заказа_jquery.js b/assets/js/checkout.js
similarity index 100%
rename from оформление_заказа_jquery.js
rename to assets/js/checkout.js
diff --git a/профиль_jquery.js b/assets/js/profile.js
similarity index 100%
rename from профиль_jquery.js
rename to assets/js/profile.js
diff --git a/assets/less/checkout.less b/assets/less/checkout.less
new file mode 100644
index 0000000..fb07c54
--- /dev/null
+++ b/assets/less/checkout.less
@@ -0,0 +1,142 @@
+.error-message {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+}
+
+.form__input.error {
+ border-color: #ff0000;
+}
+
+.form__group {
+ position: relative;
+ margin-bottom: 15px;
+}
+
+/* Стили для сообщений внизу страницы */
+.page-messages {
+ position: fixed;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 1000;
+ width: 90%;
+ max-width: 500px;
+}
+
+.message {
+ padding: 15px;
+ margin: 10px 0;
+ border-radius: 5px;
+ text-align: center;
+ font-weight: bold;
+ display: none;
+}
+
+.message.error {
+ background-color: #ffebee;
+ color: #c62828;
+ border: 1px solid #ffcdd2;
+}
+
+.message.success {
+ background-color: #e8f5e9;
+ color: #453227;
+ border: 1px solid #c8e6c9;
+}
+
+.message.warning {
+ background-color: #fff3e0;
+ color: #ef6c00;
+ border: 1px solid #ffe0b2;
+}
+
+.privacy-error {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+ text-align: center;
+}
+
+/* Дополнительные стили для формы регистрации */
+.input-group {
+ position: relative;
+ margin-bottom: 20px;
+}
+
+.profile-form input.error {
+ border-color: #ff0000;
+ background-color: #fff5f5;
+}
+
+.privacy-checkbox {
+ margin: 20px 0;
+ text-align: center;
+}
+
+.privacy-checkbox label {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ cursor: pointer;
+ font-size: 14px;
+}
+
+.privacy-checkbox input[type="checkbox"] {
+ margin: 0;
+}
+
+/* Исправление отступов для страницы регистрации */
+.profile-page-main {
+ padding: 40px 0;
+ min-height: calc(100vh - 200px);
+}
+
+/* Убедимся, что контейнер не перекрывает шапку и футер */
+.profile-container {
+ margin: 0 auto;
+ position: relative;
+ z-index: 1;
+}
+
+.input-hint {
+ font-size: 12px;
+ color: #666;
+ margin-top: 5px;
+}
+
+/* Стили для страницы входа */
+.form-options {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 20px 0;
+}
+
+.remember-me {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 14px;
+ color: #453227;
+}
+
+.remember-me input[type="checkbox"] {
+ width: 16px;
+ height: 16px;
+ cursor: pointer;
+}
+
+.forgot-password {
+ font-size: 14px;
+ color: #453227;
+ text-decoration: underline;
+}
+
+.forgot-password:hover {
+ color: #617365;
+ text-decoration: none;
+}
\ No newline at end of file
diff --git a/assets/less/mixins.less b/assets/less/mixins.less
new file mode 100644
index 0000000..630b7bd
--- /dev/null
+++ b/assets/less/mixins.less
@@ -0,0 +1,86 @@
+// ===================================
+// === ПЕРЕМЕННЫЕ И МИКСИНЫ AETERNA ===
+// ===================================
+@color-primary: #617365;
+@color-secondary: #D1D1D1;
+@color-accent: #453227;
+@color-text-dark: #333;
+@color-text-light: #fff;
+@color-button: @color-accent;
+@color-beige: #A2A09A;
+
+@font-logo: 'Anek Kannada', sans-serif;
+@font-main: 'Anonymous Pro', monospace;
+@font-heading: 'Playfair Display', serif;
+
+@shadow-light: 0 5px 15px rgba(0, 0, 0, 0.2);
+@shadow-dark: 2px 2px 4px rgba(0, 0, 0, 0.3);
+
+.flex-center(@gap: 0) {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: @gap;
+}
+
+.flex-between() {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.flex-column() {
+ display: flex;
+ flex-direction: column;
+}
+
+.icon-base(@size: 18px, @hover-scale: 1.1) {
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-size: @size;
+ &:hover {
+ transform: scale(@hover-scale);
+ }
+}
+
+.image-overlay() {
+ position: absolute;
+ inset: 0;
+ .flex-center(15px);
+ flex-direction: column;
+ text-align: center;
+ background-color: rgba(0, 0, 0, 0.4);
+ padding: 20px;
+ color: @color-text-light;
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
+ transition: all 0.3s ease;
+}
+
+.menu-base() {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ width: 250px;
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
+ padding: 15px;
+ z-index: 1000;
+ margin-top: 5px;
+ display: none;
+}
+
+.input-base() {
+ width: 100%;
+ padding: 12px 15px;
+ border: 1px solid #ccc;
+ background-color: #fff;
+ font-family: @font-main;
+ font-size: 14px;
+ outline: none;
+ transition: border-color 0.3s ease;
+ &:focus {
+ border-color: @color-primary;
+ }
+}
+
diff --git a/assets/less/style.less b/assets/less/style.less
new file mode 100644
index 0000000..667a7f4
--- /dev/null
+++ b/assets/less/style.less
@@ -0,0 +1,3177 @@
+@import "mixins.less";
+// =======================
+// === БАЗОВЫЕ СТИЛИ ===
+// =======================
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+html, body {
+ height: 100%;
+}
+
+html {
+ scroll-behavior: smooth;
+}
+
+body {
+ font-family: @font-main;
+ background-color: @color-secondary;
+ color: @color-text-dark;
+ line-height: 1.6;
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+}
+
+.container {
+ max-width: 1210px;
+ margin: 0 auto;
+ padding: 0 20px;
+}
+
+ul {
+ list-style: none;
+}
+
+a {
+ text-decoration: none;
+ color: inherit;
+ transition: all 0.3s ease;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: @font-heading;
+ margin: 0;
+}
+
+p, li, span {
+ font-family: @font-main;
+}
+
+// =======================
+// === КОМПОНЕНТЫ ===
+// =======================
+
+.logo, .footer-logo {
+ font: bold 32px/1 @font-logo;
+ letter-spacing: 2px;
+ text-shadow: @shadow-dark;
+ flex-shrink: 0;
+}
+
+.btn {
+ padding: 12px 30px;
+ border: none;
+ cursor: pointer;
+ font-size: 14px;
+ text-transform: uppercase;
+ transition: all 0.3s ease;
+ font-family: @font-main;
+
+ &.primary-btn {
+ background-color: @color-button;
+ color: @color-text-light;
+
+ &:hover {
+ background-color: lighten(@color-button, 10%);
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+ }
+}
+
+.number-circle {
+ .flex-center();
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ background-color: @color-button;
+ color: @color-text-light;
+ font-size: 16px;
+ font-weight: bold;
+ flex-shrink: 0;
+}
+
+.breadcrumbs {
+ font-size: 14px;
+ margin-bottom: 20px;
+ color: #666;
+
+ a {
+ color: #666;
+ opacity: 0.7;
+ &:hover { opacity: 1; }
+ }
+
+ .current-page {
+ font-weight: bold;
+ color: @color-text-dark;
+ }
+}
+
+// =======================
+// === ШАПКА САЙТА ===
+// =======================
+.header {
+ background-color: @color-secondary;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+ z-index: 1000;
+
+ &__top, &__bottom {
+ padding: 15px 0;
+ .container {
+ .flex-between();
+ gap: 20px;
+ }
+ }
+
+ &__bottom {
+ padding: 10px 0;
+ border-top: 1px solid rgba(0, 0, 0, 0.05);
+
+ .catalog-link.active-catalog {
+ background-color: rgba(0, 0, 0, 0.08);
+ pointer-events: none;
+ }
+ }
+
+ .search-catalog {
+ .flex-center();
+ border: 2px solid @color-text-dark;
+ background-color: #fff;
+ max-width: 600px;
+ width: 100%;
+ margin: 0 auto;
+ overflow: hidden;
+
+ .catalog-dropdown {
+ position: relative;
+ background-color: #f8f8f8;
+ padding: 10px 15px 10px 25px;
+ font-size: 18px;
+ cursor: pointer;
+ border-right: 1px solid @color-text-dark;
+ .flex-center(10px);
+ width: 200px;
+ flex-shrink: 0;
+
+ &__menu {
+ .menu-base();
+ li {
+ padding: 8px 0;
+ cursor: pointer;
+ transition: color 0.3s;
+ border-bottom: 1px solid #f0f0f0;
+ &:last-child { border-bottom: none; }
+ &:hover { color: @color-accent; }
+ }
+ }
+ &:hover &__menu { display: block; }
+ }
+
+ .search-box {
+ .flex-center();
+ padding: 0 15px;
+ flex-grow: 1;
+ position: relative;
+ font-size: 15px;
+
+ input {
+ border: none;
+ padding: 10px 30px 10px 0;
+ outline: none;
+ font-size: 16px;
+ width: 100%;
+ text-align: left;
+ }
+
+ .search-icon {
+ font-size: 20px;
+ width: 24px;
+ height: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ }}
+
+ &__icons--top {
+ .flex-center(15px);
+ flex-shrink: 0;
+ .icon { .icon-base(); font-size: 20px;}
+ }
+
+ .nav-list {
+ .flex-center(30px);
+ font-size: 18px;
+ a {
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
+ &:hover { text-shadow: @shadow-dark; }
+ &.active {
+ border-bottom: 2px solid @color-button;
+ padding-bottom: 5px;
+ text-shadow: @shadow-dark;
+ }
+ &[href="#footer"] {
+ cursor: pointer;
+ }
+ }
+ }
+
+ .catalog-link {
+ .flex-center(10px);
+ border-radius: 4px;
+ white-space: nowrap;
+ font-size: 18px;
+ padding: 10px 18px;
+ &:hover { background-color: rgba(0, 0, 0, 0.05); }
+ }
+
+ .header-phone {
+ font-weight: bold;
+ color: @color-button;
+ flex-shrink: 0;
+ }
+}
+
+// =======================
+// === ОСНОВНЫЕ СЕКЦИИ ===
+// =======================
+.hero {
+ padding: 15px 0;
+
+ &__content {
+ .flex-center(50px);
+ min-height: 60vh;
+ align-items: center;
+ }
+
+ &__image-block {
+ position: relative;
+ flex: 0 0 40%;
+ max-width: 600px;
+ height: 600px;
+ .flex-center();
+
+ .hero__circle {
+ position: absolute;
+ width: 450px;
+ height: 450px;
+ background-color: @color-primary;
+ border-radius: 50%;
+ z-index: 1;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+ .hero__img {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ z-index: 2;
+ }
+ }
+
+ &__text-block {
+ flex: 0 0 60%;
+ padding-left: 50px;
+
+ h1 {
+ font-size: 42px;
+ font-weight: normal;
+ margin-bottom: 25px;
+ line-height: 1.3;
+ }
+
+ .hero__usp-text {
+ position: relative;
+ padding-left: 50px;
+ margin-bottom: 35px;
+ line-height: 1.7;
+ .flex-center();
+ justify-content: flex-start;
+ min-height: 40px;
+ font-size: 16px;
+
+ &::before {
+ content: "✓";
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 32px;
+ height: 32px;
+ border: 2px solid @color-button;
+ background-color: transparent;
+ color: @color-button;
+ border-radius: 50%;
+ .flex-center();
+ font-size: 16px;
+ font-weight: bold;
+ }
+ }
+
+ .btn.primary-btn {
+ margin: 25px 0 0 50px;
+ padding: 14px 35px;
+ font-size: 15px;
+ }
+ }
+}
+
+.advantages {
+ padding: 30px 0 40px;
+
+ &__header {
+ display: flex;
+ align-items: center;
+ gap: 50px;
+ margin-bottom: 40px;
+ h2 {
+ font-size: 32px;
+ font-weight: normal;
+ flex: 0 0 30%;
+ }
+ }
+
+ &__items {
+ flex: 0 0 70%;
+ display: flex;
+ gap: 30px;
+ }
+
+ .advantage-item {
+ flex: 1;
+ text-align: left;
+ position: relative;
+ padding-top: 30px;
+
+ &__number {
+ .number-circle();
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+
+ h4 {
+ font-weight: 600;
+ margin-bottom: 10px;
+ }
+ }
+}
+
+.promo-images {
+ display: flex;
+ gap: 20px;
+ margin-top: 50px;
+
+ .promo-image-col {
+ position: relative;
+ overflow: hidden;
+ border-radius: 8px;
+ flex: 1;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-5px);
+ box-shadow: @shadow-light;
+ .image-overlay-text { background-color: rgba(0, 0, 0, 0.6); }
+ img { transform: scale(1.05); }
+ .image-overlay-text h4,
+ .image-overlay-text .overlay-link { transform: translateY(0); }
+ }
+
+ img {
+ width: 100%;
+ height: 350px;
+ object-fit: cover;
+ display: block;
+ transition: transform 0.5s ease;
+ }
+
+ .image-overlay-text {
+ .image-overlay();
+ h4 {
+ font-size: 24px;
+ text-transform: uppercase;
+ line-height: 1.2;
+ margin-bottom: 15px;
+ transform: translateY(20px);
+ transition: transform 0.3s ease;
+ }
+ }
+
+ .overlay-link {
+ display: inline-block;
+ text-transform: uppercase;
+ font-weight: bold;
+ border-radius: 3px;
+ margin-top: 15px;
+ padding: 10px 25px;
+ background-color: @color-button;
+ color: @color-text-light;
+ font-size: 12px;
+ transform: translateY(20px);
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: lighten(@color-button, 10%);
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+ }
+ }
+}
+
+.about {
+ padding: 40px 0 80px;
+
+ &__content {
+ display: flex;
+ align-items: flex-start;
+ gap: 50px;
+ }
+
+ &__column {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ &--left { flex: 0 0 40%; margin-bottom: 30px; }
+ &--right {
+ flex: 0 0 60%;
+ .about__caption {
+ padding-right: 50px;
+ }
+ }
+ }
+
+ &__text-block {
+ margin-bottom: 30px;
+ h2 { margin-bottom: 15px; }
+ }
+
+ &__img {
+ width: 93%;
+ object-fit: cover;
+ display: block;
+ &--small { height: 300px; }
+ &--large { height: 450px; }
+ }
+
+ .text-justified {
+ text-align: justify;
+ color: #555;
+ }
+}
+
+.solutions {
+ padding: 0;
+ background-color: @color-secondary;
+
+ &-slider {
+ position: relative;
+ width: 100%;
+ max-width: 1200px;
+ margin: 40px auto;
+ border-radius: 8px;
+ overflow: hidden;
+
+ &__slides {
+ display: flex;
+ width: 200%;
+ height: 100%;
+ animation: slideLeftRight 10s infinite ease-in-out;
+ }
+
+ &__slide {
+ width: 50%;
+ flex-shrink: 0;
+ position: relative;
+ overflow: hidden;
+ transition: transform 0.5s ease, box-shadow 0.5s ease;
+
+ &:hover {
+ transform: scale(1.02);
+ box-shadow: 0 10px 25px rgba(0,0,0,0.3);
+ .solution-img {
+ transform: scale(1.05);
+ filter: brightness(0.8);
+ }
+ .solution-text-overlay {
+ opacity: 1;
+ transform: translateY(-5px);
+ }
+ .solution-image-link {
+ transform: translateX(-50%) translateY(-6px);
+ background-color: rgba(255,255,255,0.9);
+ color: @color-text-dark;
+ }
+ }
+ }
+
+ .solution-img {
+ width: 100%;
+ height: auto;
+ object-fit: cover;
+ display: block;
+ }
+
+ .solution-text-overlay {
+ position: absolute;
+ top: 15%;
+ left: 8%;
+ color: #493131;
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.6);
+ z-index: 2;
+ opacity: 0.9;
+ transition: opacity 0.5s ease, transform 0.5s ease;
+ h2 {
+ font-size: 35px;
+ text-transform: uppercase;
+ margin-bottom: 10px;
+ }
+ p {
+ font-size: 25px;
+ text-transform: uppercase;
+ }
+ }
+
+ .solution-image-link {
+ position: absolute;
+ bottom: 40px;
+ left: 50%;
+ transform: translateX(-50%);
+ padding: 12px 30px;
+ border: 2px solid @color-text-light;
+ color: #493131;
+ text-transform: uppercase;
+ font-size: 16px;
+ font-weight: bold;
+ background: transparent;
+ transition: 0.4s ease;
+ z-index: 2;
+ &:hover {
+ background: @color-text-light;
+ color: @color-text-dark;
+ transform: translateX(-50%) translateY(-2px);
+ }
+ }
+ }
+}
+
+@keyframes slideLeftRight {
+ 0%, 40% { transform: translateX(0); }
+ 50%, 90% { transform: translateX(-50%); }
+ 100% { transform: translateX(0); }
+}
+
+.stats {
+ padding: 0;
+ margin-top: 20px;
+
+ .container {
+ display: flex;
+ justify-content: flex-end;
+ }
+
+ &__items {
+ display: flex;
+ gap: 20px;
+ .stat-item {
+ text-align: left;
+ .stat-number {
+ font-size: 36px;
+ font-weight: bold;
+ color: @color-text-dark;
+ margin-bottom: 5px;
+ }
+ .stat-label { color: @color-text-dark; }
+ }
+ }
+}
+
+.faq {
+ padding: 50px 0;
+
+ h2 {
+ text-align: left;
+ font-size: 32px;
+ font-weight: normal;
+ margin-bottom: 40px;
+ }
+
+ &__items {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 40px 60px;
+ margin-bottom: 40px;
+ }
+
+ .faq-item {
+ flex: 0 0 calc(50% - 30px);
+ .flex-center(15px);
+ align-items: flex-start;
+ &__content h4 {
+ font-weight: 600;
+ margin-bottom: 10px;
+ }
+ }
+
+ .btn.primary-btn {
+ display: block;
+ width: 100%;
+ margin: 20px auto 80px;
+ }
+}
+
+// =======================
+// === СТИЛИ КАТАЛОГА ===
+// =======================
+.catalog-main {
+ padding: 30px 0 60px;
+ background-color: lighten(@color-secondary, 5%);
+}
+
+.catalog-wrapper {
+ display: flex;
+ gap: 20px;
+}
+
+.catalog-sidebar {
+ flex: 0 0 250px;
+ background-color: #fff;
+ padding: 20px;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
+ height: fit-content;
+}
+
+.filter-group {
+ margin-bottom: 30px;
+}
+
+.filter-title {
+ font-size: 16px;
+ font-weight: bold;
+ margin-bottom: 15px;
+ text-transform: uppercase;
+}
+
+.filter-list li {
+ padding: 5px 0;
+ font-size: 16px;
+ a {
+ color: #555;
+ transition: color 0.2s;
+ &:hover { color: @color-accent; }
+ &.active-category {
+ font-weight: bold;
+ color: @color-primary;
+ }
+ }
+}
+
+.price-range {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ width: 100%;
+
+ .range-slider {
+ width: 100%;
+
+ input[type="range"] {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 100%;
+ height: 5px;
+ background: @color-primary;
+ border-radius: 5px;
+ outline: none;
+ margin: 0;
+
+ &::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 20px;
+ height: 20px;
+ background: @color-accent;
+ border: 2px solid #fff;
+ border-radius: 50%;
+ cursor: pointer;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ background: lighten(@color-accent, 10%);
+ }
+ }
+
+ &::-moz-range-thumb {
+ width: 20px;
+ height: 20px;
+ background: @color-accent;
+ border: 2px solid #fff;
+ border-radius: 50%;
+ cursor: pointer;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ background: lighten(@color-accent, 10%);
+ }
+ }
+ }
+ }
+
+ .price-display {
+ font-size: 14px;
+ font-weight: bold;
+ text-align: center;
+ color: @color-text-dark;
+ padding: 10px;
+ background: #f8f8f8;
+ border-radius: 4px;
+ }
+}
+
+.filter-options {
+ list-style: none;
+ li {
+ display: flex;
+ align-items: center;
+ padding: 4px 0;
+ font-size: 14px;
+ }
+ label {
+ margin-left: 10px;
+ cursor: pointer;
+ color: #555;
+ }
+ input[type="checkbox"] {
+ width: 15px;
+ height: 15px;
+ cursor: pointer;
+ accent-color: @color-primary;
+ &:checked + label {
+ font-weight: bold;
+ color: @color-primary;
+ }
+ }
+}
+
+.filter-apply-btn {
+ width: 100%;
+ margin-top: 20px;
+}
+
+.catalog-products {
+ flex-grow: 1;
+}
+
+.products-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20px;
+}
+
+.product-card {
+ background-color: #fff;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ transition: transform 0.3s ease;
+ box-sizing: border-box;
+
+ &:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
+ .product-img { transform: scale(1.05); }
+ }
+}
+
+.product-image-container {
+ position: relative;
+ overflow: hidden;
+ margin-bottom: 0;
+ padding: 0;
+ height: 250px;
+ .flex-center();
+}
+
+.product-img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ display: block;
+ transition: transform 0.3s ease;
+ margin: 0;
+}
+
+.product-img1 {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ transition: transform 0.3s ease;
+ margin: 0;
+}
+
+.product-discount {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ background-color: @color-button;
+ color: @color-text-light;
+ padding: 3px 8px;
+ font-size: 12px;
+ font-weight: bold;
+ z-index: 10;
+}
+
+.product-wishlist-icon {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ color: #333;
+ font-size: 18px;
+ cursor: pointer;
+ transition: color 0.3s ease;
+ z-index: 10;
+ &:hover { color: @color-accent; }
+}
+
+.product-name {
+ font-size: 16px;
+ font-weight: bold;
+ margin-bottom: 5px;
+}
+
+.product-details {
+ font-size: 13px;
+ color: #777;
+ margin-bottom: 10px;
+ flex-grow: 1;
+}
+
+.product-price {
+ font-size: 18px;
+ font-weight: bold;
+ color: @color-button;
+}
+
+.product-card.small { flex: 0 0 300px; max-width: 300px; height: 200px; }
+.product-card.small1 { flex: 0 0 320px; max-width: 320px; height: 250px;width: 320px; }
+.product-card.large { flex: 0 0 580px; max-width: 580px; height: 380px; }
+.product-card.wide { flex: 0 0 240px; max-width: 240px; height: 250px; }
+.product-card.wide1 { flex: 0 0 350px; max-width: 350px; height: 250px; }
+.product-card.wide2 { flex: 0 0 560px; max-width: 560px; height: 260px; }
+.product-card.wide2_1 { flex: 0 0 560px; max-width: 560px; height: 260px; margin: -280px 0 0; }
+.product-card.wide3 {
+ flex: 0 0 320px; max-width: 320px; height: 540px;
+ .product-image-container { height: 580px; }
+}
+.product-card.wide4 {
+ flex: 0 0 545px; max-width: 545px; margin: -270px 0 0; height: 250px;
+ .product-image-container { padding: 0; justify-content: flex-start; }
+ .product-img { margin-left: 0; align-self: flex-start; object-position: left center; }
+}
+.product-card.tall { flex: 0 0 300px; max-width: 300px; margin: -180px 0 0; height: 430px; }
+.product-card.full-width { flex: 0 0 100%; margin: -20px 0 0; max-width: 900px; height: 300px;}
+
+.product-card.full-width {
+ flex: 0 0 100%;
+ max-width: 100%;
+ height: 300px;
+
+ .product-image-container {
+ height: 100%;
+ padding: 0;
+ margin: 0;
+
+ .product-img1 {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ margin: 0;
+ padding: 0;
+ }
+ }
+}
+
+.product-card.tall .product-image-container,
+.product-card.large .product-image-container { height: 430px; }
+
+// =======================
+// === СТРАНИЦА ТОВАРА ===
+// =======================
+.product__section {
+ display: flex;
+ gap: 0;
+ margin: 30px 0;
+}
+
+.product__gallery, .product__info {
+ flex: 1;
+}
+
+.product__main-image {
+ margin-bottom: 15px;
+}
+
+.product__image {
+ width: 500px;
+ height: 300px;
+ border-radius: 4px;
+}
+
+.product__thumbnails {
+ display: flex;
+ gap: 10px;
+}
+
+.product__thumbnail {
+ border: none;
+ background: none;
+ cursor: pointer;
+ padding: 0;
+}
+
+.product__thumbnail img {
+ width: 245px;
+ height: 150px;
+ object-fit: cover;
+ border-radius: 4px;
+}
+
+.product__title {
+ font-size: 30px;
+ margin-bottom: 35px;
+}
+
+.product__rating {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 30px;
+}
+
+.product__color-selector {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 40px;
+}
+
+.product__color-option {
+ width: 45px;
+ height: 45px;
+ border-radius: 50%;
+ border: 2px solid transparent;
+ cursor: pointer;
+ transition: transform 0.3s ease;
+
+ &:hover{
+ transform: translateY(-2px);
+ }
+}
+
+.product__color-option.active {
+ border-color: @color-primary;
+}
+
+.product__description {
+ margin-bottom: 65px;
+ line-height: 1.5;
+}
+
+.product__details-link {
+ display: inline-block;
+ margin-bottom: 20px;
+ color: @color-primary;
+ font-weight: bold;
+}
+
+.product__purchase {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 35px;
+}
+
+.product__price {
+ font-size: 24px;
+ font-weight: bold;
+}
+
+.product__quantity {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.product__qty-btn {
+ width: 30px;
+ height: 30px;
+ background: @color-button;
+ color: @color-text-light;
+ border: none;
+ border-radius: 50%;
+ cursor: pointer;
+ font-weight: bold;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background: lighten(@color-button, 10%);
+ transform: scale(1.1);
+ }
+}
+
+.product__qty-value {
+ font-weight: bold;
+ min-width: 30px;
+ text-align: center;
+}
+
+.product__actions {
+ display: flex;
+ gap: 15px;
+}
+
+.product__btn {
+ flex: 1;
+ padding: 12px 20px;
+ border: none;
+ border-radius: 4px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+}
+
+.product__btn.primary {
+ background: @color-button;
+ color: @color-text-light;
+
+ &:hover {
+ background: lighten(@color-button, 10%);
+ }
+}
+
+.product__btn.secondary {
+ background: transparent;
+ border: 1px solid @color-button;
+ color: @color-button;
+
+ &:hover {
+ background: @color-button;
+ color: @color-text-light;
+ }
+}
+
+.similar {
+ margin: 60px 0;
+}
+
+.similar__title {
+ margin-bottom: 30px;
+ font-size: 28px;
+ font-weight: bold;
+}
+
+.similar__grid {
+ display: flex;
+ gap: 25px;
+ flex-wrap: wrap;
+ justify-content: space-between;
+}
+
+.similar__card {
+ flex: 0 0 calc(33.333% - 17px);
+ min-width: 320px;
+ background: @color-secondary;
+ border-radius: 12px;
+ overflow: hidden;
+ transition: all 0.3s ease;
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
+
+ &:hover {
+ transform: translateY(-8px);
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+ }
+}
+
+.similar__card-image {
+ height: 300px;
+ overflow: hidden;
+ background: white;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ transition: transform 0.3s ease;
+
+ &:hover {
+ transform: scale(1.05);
+ }
+ }
+}
+
+.similar__card-content {
+ padding: 25px;
+}
+
+.similar__card-title {
+ font-weight: bold;
+ margin-bottom: 10px;
+ font-size: 20px;
+ color: @color-text-dark;
+}
+
+.similar__card-description {
+ font-size: 15px;
+ margin-bottom: 15px;
+ color: #666;
+ line-height: 1.5;
+}
+
+.similar__card-price {
+ font-weight: bold;
+ font-size: 22px;
+ color: @color-button;
+}
+
+@media (max-width: 1024px) {
+ .similar {
+ &__card {
+ flex: 0 0 calc(50% - 13px);
+ min-width: 280px;
+ }
+ }
+}
+
+@media (max-width: 768px) {
+ .similar {
+ &__grid {
+ justify-content: center;
+ }
+
+ &__card {
+ flex: 0 0 100%;
+ max-width: 400px;
+ }
+ }
+}
+
+// =======================
+// === КОРЗИНА И ЗАКАЗ ===
+// =======================
+.main__content {
+ display: flex;
+ gap: 40px;
+ margin: 30px 0;
+
+ .products {
+ flex: 1;
+ }
+
+ .order {
+ flex: 0 0 65%;
+ padding: 40px;
+
+ &__header {
+ .flex-between();
+ margin-bottom: 20px;
+ }
+
+ &__title {
+ font-family: @font-logo;
+ font-size: 28px;
+ color: @color-text-dark;
+ margin: 0;
+ }
+
+ &__total {
+ font-weight: bold;
+ color: @color-text-dark;
+ }
+
+ &__section {
+ margin-bottom: 25px;
+ }
+
+ &__section-title {
+ font-family: @font-logo;
+ margin-bottom: 15px;
+ font-size: 18px;
+ color: @color-text-dark;
+ }
+ }
+}
+
+.products {
+ &__title {
+ font-family: @font-logo;
+ margin-bottom: 20px;
+ font-size: 24px;
+ color: @color-text-dark;
+ }
+
+ &__list {
+ .flex-column();
+ gap: 20px;
+ }
+
+ &__item {
+ background-color: @color-secondary;
+ border-radius: 8px;
+ padding: 20px;
+ display: flex;
+ gap: 15px;
+ border: 1px solid @color-secondary;
+ transition: transform 0.3s ease;
+ align-items: flex-start;
+ position: relative;
+
+ &:hover {
+ transform: translateY(-2px);
+ }
+ }
+
+ &__image {
+ width: 300px;
+ height: 200px;
+ border-radius: 4px;
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ }
+
+ .product-img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ transition: transform 0.3s ease;
+ margin: 0;
+ }
+
+ &__details {
+ flex: 1;
+ .flex-column();
+ justify-content: space-between;
+ align-items: flex-start;
+ min-height: 200px;
+ }
+
+ &__name {
+ font-weight: bold;
+ margin-bottom: 5px;
+ color: @color-accent;
+ font-size: 18px;
+ font-family: @font-main;
+ }
+
+ &__price {
+ font-weight: bold;
+ font-size: 18px;
+ margin-bottom: 15px;
+ color: @color-text-dark;
+ }
+
+ &__controls {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ margin-top: auto;
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ &__quantity {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+
+ &__qty-btn {
+ width: 30px;
+ height: 30px;
+ background-color: @color-text-dark;
+ color: @color-text-light;
+ border: none;
+ border-radius: 50%;
+ cursor: pointer;
+ .flex-center();
+ font-family: @font-main;
+ font-weight: bold;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ }
+ }
+
+ &__qty-value {
+ font-weight: bold;
+ min-width: 30px;
+ text-align: center;
+ font-size: 16px;
+ }
+
+ &__cart-icon {
+ background-color: transparent;
+ color: @color-text-dark;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ border: 2px solid @color-text-dark;
+ margin-left: 20px;
+
+ &:hover {
+ transform: scale(1.1);
+ }
+
+ i { font-size: 18px; }
+ }
+}
+
+.form {
+ &__group { margin-bottom: 15px; }
+ &__label {
+ display: block;
+ margin-bottom: 5px;
+ font-weight: bold;
+ color: #000000;
+ }
+ &__input {
+ width: 100%;
+ padding: 14px 16px;
+ border: 2px solid #ccc;
+ font-family: @font-main;
+ font-size: 15px;
+ transition: border-color 0.3s ease;
+
+ &:focus {
+ border-color: @color-primary;
+ }
+
+ &:hover {
+ border-color: darken(#ccc, 10%);
+ }
+ &::placeholder {
+ font-style: italic;
+ color: #999;
+ }
+ }
+ &__row {
+ display: flex;
+ gap: 20px;
+ justify-content: space-between;
+ }
+ &__input--half {
+ width: 100%;
+ }
+ &__radio-group {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ margin-top: 20px;
+ }
+ &__radio-label {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ color: @color-text-dark;
+ position: relative;
+ padding-left: 30px;
+ flex: 1;
+
+ &:hover {
+ .form__custom-radio {
+ border-color: lighten(@color-accent, 10%);
+ }
+ }
+ }
+ &__radio-input {
+ position: absolute;
+ opacity: 0;
+ cursor: pointer;
+ }
+ &__custom-radio {
+ position: absolute;
+ left: 0;
+ height: 20px;
+ width: 20px;
+ background-color: @color-secondary;
+ border: 2px solid @color-accent;
+ border-radius: 50%;
+ transition: border-color 0.3s ease;
+ }
+ &__radio-input:checked ~ &__custom-radio {
+ background-color: @color-accent;
+
+ &:after {
+ content: "";
+ position: absolute;
+ display: block;
+ top: 4px;
+ left: 4px;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: white;
+ }
+ }
+}
+
+.divider {
+ height: 1px;
+ background-color: #999;
+ margin: 20px 0;
+}
+
+.promo {
+ display: flex;
+ margin-bottom: 20px;
+
+ &__input {
+ flex: 1;
+ padding: 10px;
+ border: 1px solid #000;
+ background-color: @color-secondary;
+ font-family: @font-main;
+ height: auto;
+ min-height: 48px;
+
+ &:hover {
+ border-color: @color-primary;
+ }
+
+ &::placeholder {
+ font-style: italic;
+ color: #999;
+ }
+ }
+
+ &__btn {
+ background-color: @color-accent;
+ color: @color-secondary;
+ border: none;
+ padding: 10px 60px;
+ cursor: pointer;
+ font-family: @font-main;
+ font-size: 18px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: lighten(@color-accent, 10%);
+ transform: translateY(-2px);
+ }
+ }
+}
+
+.summary {
+ margin-bottom: 20px;
+
+ &__item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ color: @color-text-dark;
+
+ &.total {
+ font-weight: bold;
+ font-size: 18px;
+ padding-top: 10px;
+ margin-top: 10px;
+ }
+ }
+}
+
+.order-btn {
+ width: 100%;
+ background-color: @color-accent;
+ color: @color-secondary;
+ border: none;
+ padding: 15px;
+ border-radius: 4px;
+ font-size: 18px;
+ cursor: pointer;
+ margin-bottom: 10px;
+ font-family: @font-main;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: lighten(@color-accent, 10%);
+ transform: translateY(-2px);
+ }
+}
+
+.privacy {
+ display: flex;
+ gap: 8px;
+ font-size: 16px;
+ color: #666;
+ margin-bottom: 20px;
+
+ input[type="checkbox"] {
+ width: 18px;
+ height: 18px;
+ cursor: pointer;
+ }
+}
+
+.services {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ flex-wrap: wrap;
+ gap: 24px;
+ margin-bottom: 24px;
+
+ &__title {
+ font-family: @font-logo;
+ margin-bottom: 10px;
+ font-size: 18px;
+ color: @color-text-dark;
+ display: block;
+ width: 100%;
+ }
+
+ &__item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 8px;
+ color: @color-text-dark;
+ width: 100%;
+ }
+}
+
+.cart-icon {
+ position: relative;
+}
+
+.cart-count {
+ position: absolute;
+ top: -8px;
+ right: -8px;
+ background: @color-accent;
+ color: @color-text-light;
+ border-radius: 50%;
+ width: 18px;
+ height: 18px;
+ font-size: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.form__input.error {
+ border-color: #ff4444;
+ box-shadow: 0 0 5px rgba(255, 68, 68, 0.3);
+}
+
+.empty-cart {
+ text-align: center;
+ padding: 40px;
+ color: #666;
+ font-size: 18px;
+}
+
+// =======================
+// === АВТОРИЗАЦИЯ ===
+// =======================
+.profile-page-main {
+ .flex-center();
+ min-height: 80vh;
+ padding: 40px 0;
+ background-color: lighten(@color-secondary, 5%);
+ z-index: 1;
+
+ .profile-container {
+ display: flex;
+ width: 100%;
+ max-width: 1000px;
+ min-height: 600px;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
+ background-color: @color-text-light;
+ }
+
+ .profile-left-col {
+ flex: 0 0 35%;
+ background-color: @color-primary;
+ color: @color-text-light;
+ display: flex;
+ justify-content: flex-start;
+ align-items: flex-start;
+ padding: 40px;
+ .logo {
+ font-size: 32px;
+ font-weight: normal;
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
+ color: @color-text-light;
+ }
+ }
+
+ .profile-right-col {
+ flex: 0 0 65%;
+ .flex-center();
+ padding: 40px;
+ .profile-form-block {
+ width: 100%;
+ max-width: 400px;
+ h2 {
+ font-size: 28px;
+ font-weight: normal;
+ margin-bottom: 40px;
+ text-align: left;
+ color: @color-text-dark;
+ }
+ }
+ }
+
+ .profile-form {
+ .input-group {
+ margin-bottom: 20px;
+ label {
+ display: block;
+ font-size: 12px;
+ font-weight: bold;
+ color: @color-text-dark;
+ margin-bottom: 5px;
+ text-transform: uppercase;
+ }
+ }
+
+ input[type="text"],
+ input[type="email"],
+ input[type="tel"] {
+ .input-base();
+ }
+
+ .password-link {
+ display: block;
+ text-align: left;
+ font-size: 13px;
+ color: @color-text-dark;
+ text-decoration: underline;
+ margin: 10px 0 20px;
+ &:hover {
+ color: @color-accent;
+ text-decoration: none;
+ }
+ }
+
+ .save-btn {
+ padding: 15px 30px;
+ border: none;
+ cursor: pointer;
+ font-size: 15px;
+ text-transform: uppercase;
+ transition: all 0.3s ease;
+ font-family: @font-main;
+ width: 100%;
+ margin-top: 20px;
+ background-color: @color-primary;
+ color: @color-text-light;
+
+ &:hover {
+ background-color: lighten(@color-primary, 10%);
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+ }
+
+ .auth-actions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 25px;
+ padding-top: 20px;
+ border-top: 1px solid #eee;
+
+ .auth-text {
+ font-size: 13px;
+ color: @color-text-dark;
+ }
+
+ .login-btn {
+ background-color: transparent;
+ color: @color-accent;
+ border: 1px solid @color-accent;
+ padding: 10px 25px;
+ font-size: 13px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: @color-primary;
+ color: @color-text-light;
+ }
+ }
+ }
+ }
+}
+
+// =======================
+// === СЕКЦИЯ УСЛУГ ===
+// =======================
+.services-section {
+ padding: 60px 0;
+ background-color: @color-secondary;
+}
+
+.services__wrapper {
+ display: flex;
+ flex-direction: column;
+ gap: 30px;
+}
+
+.services__top-row {
+ display: flex;
+ gap: 30px;
+ justify-content: center;
+
+ @media (max-width: 768px) {
+ flex-direction: column;
+ align-items: center;
+ }
+}
+
+.service-card {
+ border-radius: 8px;
+ padding: 40px;
+ min-height: 200px;
+ text-align: center;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-5px);
+ box-shadow: @shadow-light;
+ }
+
+ &--green {
+ background: @color-primary;
+ color: @color-text-light;
+ flex: 1;
+ max-width: 450px;
+ }
+
+ &--beige {
+ background: @color-beige;
+ color: @color-text-light;
+ width: 100%;
+ max-width: 930px;
+ margin: 0 auto;
+ }
+
+ &__title {
+ font-family: @font-logo;
+ font-size: 24px;
+ font-weight: bold;
+ margin-bottom: 15px;
+ text-transform: uppercase;
+ }
+
+ &__text {
+ font-family: @font-main;
+ font-size: 16px;
+ line-height: 1.6;
+ margin: 0;
+ }
+}
+
+// =======================
+// === ФУТЕР ===
+// =======================
+.footer {
+ background-color: @color-primary;
+ color: black;
+ padding: 40px 0 10px;
+ position: relative;
+ z-index: 1000;
+
+ &::before {
+ content: '';
+ display: block;
+ position: absolute;
+ top: -80px;
+ left: 0;
+ width: 100%;
+ height: 1px;
+ visibility: hidden;
+ }
+
+ &__content {
+ display: flex;
+ gap: 20px;
+ padding-bottom: 30px;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+ }
+
+ &__col {
+ flex: 1;
+ &--logo { flex: 1.5; }
+ h5 {
+ margin-bottom: 15px;
+ font-size: 14px;
+ text-transform: uppercase;
+ }
+ ul li {
+ margin-bottom: 8px;
+ a:hover { text-decoration: underline; }
+ }
+ .social-icons,
+ .payment-icons {
+ .flex-center(15px);
+ justify-content: flex-start;
+ margin-top: 10px;
+ }
+ .social-icons .icon {
+ .icon-base(20px, 1.1);
+ color: black;
+ &:hover { color: @color-accent; }
+ }
+ .payment-icons .pay-icon {
+ .icon-base(24px, 1.05);
+ color: black;
+ }
+ }
+
+ .copyright {
+ text-align: center;
+ font-size: 12px;
+ padding-top: 20px;
+ color: rgba(255, 255, 255, 0.6);
+ }
+}
+
+// =======================
+// === ДОСТАВКА ===
+// =======================
+.delivery-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 40px 20px;
+}
+
+.delivery-content h1 {
+ font-family: @font-logo;
+ font-size: 42px;
+ text-align: center;
+ margin-bottom: 50px;
+ color: #453227;
+}
+
+.delivery-section {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 30px;
+ margin-bottom: 60px;
+}
+
+.delivery-card {
+ background: white;
+ padding: 30px;
+ border-radius: 12px;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+ text-align: center;
+ transition: transform 0.3s ease;
+ flex: 1;
+ min-width: 350px;
+ max-width: 400px;
+}
+
+.delivery-card:hover {
+ transform: translateY(-5px);
+}
+
+.delivery-icon {
+ font-size: 48px;
+ color: #617365;
+ margin-bottom: 20px;
+}
+
+.delivery-card h3 {
+ font-family: @font-logo;
+ font-size: 24px;
+ margin-bottom: 20px;
+ color: #453227;
+}
+
+.delivery-details {
+ text-align: left;
+}
+
+.detail-item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 12px;
+ padding-bottom: 12px;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.detail-label {
+ font-weight: bold;
+ color: #333;
+}
+
+.detail-value {
+ color: #617365;
+ text-align: right;
+}
+
+// =======================
+// === ГАРАНТИЯ ===
+// =======================
+.warranty-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 40px 20px;
+}
+
+.warranty-content h1 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 42px;
+ text-align: center;
+ margin-bottom: 50px;
+ color: #453227;
+}
+
+.warranty-overview {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 25px;
+ margin-bottom: 60px;
+}
+
+.warranty-card {
+ background: white;
+ padding: 30px;
+ border-radius: 12px;
+ text-align: center;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+ transition: transform 0.3s ease;
+ flex: 1;
+ min-width: 250px;
+ max-width: 280px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.warranty-card:hover {
+ transform: translateY(-5px);
+}
+
+.warranty-icon {
+ font-size: 48px;
+ color: #617365;
+ margin-bottom: 20px;
+}
+
+.warranty-card h3 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 20px;
+ margin-bottom: 15px;
+ color: #453227;
+}
+
+.warranty-period {
+ font-size: 24px;
+ font-weight: bold;
+ color: #617365;
+ margin-top: auto;
+}
+
+.coverage-section {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 40px;
+ margin-bottom: 60px;
+}
+
+.coverage-covered,
+.coverage-not-covered {
+ flex: 1;
+ min-width: 300px;
+}
+
+.coverage-section h2 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 24px;
+ margin-bottom: 25px;
+ color: #453227;
+}
+
+.coverage-list {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.coverage-item {
+ display: flex;
+ align-items: flex-start;
+ gap: 15px;
+ padding: 20px;
+ border-radius: 8px;
+ background: white;
+ box-shadow: 0 3px 10px rgba(0,0,0,0.1);
+}
+
+.coverage-item.covered i {
+ color: #28a745;
+ font-size: 20px;
+ margin-top: 2px;
+ flex-shrink: 0;
+}
+
+.coverage-item.not-covered i {
+ color: #dc3545;
+ font-size: 20px;
+ margin-top: 2px;
+ flex-shrink: 0;
+}
+
+.coverage-text {
+ flex: 1;
+}
+
+.coverage-item h4 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 16px;
+ margin-bottom: 5px;
+ color: #333;
+}
+
+.card {
+ min-height: 250px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: @color-text-light;
+ text-align: center;
+
+ &--green {
+ background: @color-primary;
+ flex: 0 1 450px;
+ max-width: 450px;
+ }
+
+ &--beige {
+ background: @color-beige;
+ color: @color-text-dark;
+ flex: 0 1 925px;
+ max-width: 925px;
+ }
+}
+
+.design-section {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+ .card { width: 100%; }
+}
+
+// =======================
+// === АДАПТИВНОСТЬ ===
+// =======================
+@media (max-width: 1240px) {
+ .catalog-wrapper { gap: 20px; }
+ .catalog-sidebar { flex: 0 0 200px; }
+ .products-container {
+ gap: 15px;
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .product-card.small1 {
+ margin-top: 100px;
+ }
+
+ .product-card.small,
+ .product-card.small1,
+ .product-card.large,
+ .product-card.wide,
+ .product-card.wide1,
+ .product-card.wide2,
+ .product-card.wide2_1,
+ .product-card.wide4 {
+ flex: 0 0 calc(33.333% - 10px);
+ max-width: calc(33.333% - 10px);
+ height: 180px;
+ margin: 0;
+
+ .product-image-container {
+ height: 180px;
+ }
+ }
+
+ .product-card.wide3 {
+ flex: 0 0 calc(25% - 10px);
+ max-width: calc(25% - 10px);
+ height: 300px;
+ margin: 0;
+
+ .product-image-container {
+ height: 350px;
+ }
+ }
+
+ .product-card.tall {
+ flex: 0 0 calc(25% - 10px);
+ max-width: calc(25% - 10px);
+ height: 300px;
+ margin: 0;
+
+ .product-image-container {
+ height: 300px;
+ }
+ }
+
+ .product-card.full-width {
+ flex: 0 0 100%;
+ max-width: 100%;
+ height: 300px;
+ margin: 0;
+
+ .product-image-container {
+ height: 300px;
+ }
+ }
+
+ .product-card.small { order: 1; }
+ .product-card.large { order: 2; }
+ .product-card.wide { order: 3; }
+
+ .product-card.small1 { order: 11; }
+ .product-card.wide2 { order: 12; }
+ .product-card.wide2_1 { order: 13; }
+
+ .product-card.wide3 { order: 21; }
+ .product-card.tall { order: 22; }
+
+ .product-card.wide3 { order: 31; }
+
+ .product-card.full-width { order: 41; flex-basis: 100%; }
+
+ .main__content {
+ gap: 20px;
+ .products {
+ flex: 0 0 35%;
+ .products__image {
+ width: 250px;
+ height: 180px;
+ }
+ }
+ .order {
+ flex: 0 0 60%;
+ padding: 30px;
+
+ .order__title {
+ font-size: 24px;
+ }
+
+ .order__section-title {
+ font-size: 16px;
+ }
+ }
+ }
+
+ .solutions-slider {
+ &__slide {
+ .solution-text-overlay {
+ top: 10%;
+ left: 5%;
+ h2 {
+ font-size: 26px;
+ margin-bottom: 5px;
+ line-height: 1.2;
+ }
+ p {
+ font-size: 18px;
+ line-height: 1.2;
+ }
+ }
+ .solution-image-link {
+ bottom: 70px;
+ padding: 10px 25px;
+ font-size: 14px;
+ }
+ }
+ }
+
+ .product__image {
+ width: 350px;
+ height: 250px;
+ }
+
+ .product__thumbnail img {
+ width: 170px;
+ height: 120px;
+ }
+}
+
+@media (max-width: 1024px) {
+ .main__content {
+ gap: 25px;
+ .products {
+ flex: 0 0 30%;
+ .products__image {
+ width: 200px;
+ height: 150px;
+ }
+
+ .products__name {
+ font-size: 16px;
+ }
+
+ .products__price {
+ font-size: 16px;
+ }
+ }
+ .order {
+ flex: 0 0 60%;
+ padding: 25px;
+
+ .order__title {
+ font-size: 22px;
+ }
+
+ .form__input {
+ padding: 12px 14px;
+ font-size: 14px;
+ }
+
+ .promo__btn {
+ padding: 10px 40px;
+ font-size: 16px;
+ }
+ }
+ }
+}
+
+@media (max-width: 768px) {
+ .container { padding: 0 15px; }
+
+ .delivery-section {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .delivery-card {
+ min-width: 100%;
+ max-width: 100%;
+ }
+
+ .delivery-content h1 {
+ font-size: 32px;
+ }
+
+ .warranty-overview {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .warranty-card {
+ max-width: 100%;
+ width: 100%;
+ }
+
+ .coverage-section {
+ flex-direction: column;
+ }
+
+ .warranty-content h1 {
+ font-size: 32px;
+ }
+
+ .header__top .container,
+ .header__bottom .container,
+ .hero__content,
+ .advantages__header,
+ .about__content,
+ .advantages__items,
+ .promo-images,
+ .stats__items,
+ .faq__items,
+ .catalog-wrapper,
+ .main__content {
+ flex-direction: column;
+ gap: 30px;
+ }
+
+ .search-catalog {
+ order: 3;
+ width: 100%;
+ max-width: 100%;
+ }
+
+ .nav-list {
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 15px;
+ }
+
+ .hero {
+ &__image-block {
+ flex: none;
+ max-width: 400px;
+ height: 400px;
+ }
+ &__circle {
+ width: 380px;
+ height: 380px;
+ }
+ &__text-block {
+ flex: none;
+ padding-left: 0;
+ text-align: center;
+ h1 { font-size: 32px; }
+ .hero__usp-text {
+ padding-left: 0;
+ justify-content: center;
+ &::before { display: none; }
+ }
+ .btn.primary-btn { margin-left: 0; }
+ }
+ }
+
+ .advantages__header h2,
+ .faq h2 { font-size: 28px; }
+
+ .faq-item,
+ .stat-item {
+ flex: none;
+ .flex-center();
+ text-align: center;
+ }
+
+ .stats .container { justify-content: center; }
+ .catalog-dropdown__menu { width: 200px; }
+
+ .catalog-sidebar { width: 100%; flex: none; }
+ .products-container { gap: 15px; }
+
+ .product-card.small,
+ .product-card.small1,
+ .product-card.large,
+ .product-card.wide,
+ .product-card.wide1,
+ .product-card.wide2,
+ .product-card.wide2_1,
+ .product-card.wide3,
+ .product-card.wide4,
+ .product-card.tall,
+ .product-card.full-width {
+ flex: 0 0 100%;
+ max-width: 100%;
+ height: 250px;
+ margin: 0;
+
+ .product-image-container {
+ height: 200px;
+ }
+ }
+
+ .main__content {
+ flex-direction: column;
+ gap: 20px;
+
+ .products,
+ .order {
+ flex: 0 0 100%;
+ width: 100%;
+ }
+
+ .products {
+ .products__item {
+ flex-direction: column;
+ text-align: center;
+ gap: 15px;
+ }
+
+ .products__image {
+ width: 100%;
+ height: 200px;
+ justify-content: center;
+ }
+
+ .products__details {
+ min-height: auto;
+ align-items: center;
+ }
+
+ .products__controls {
+ justify-content: center;
+ margin-top: 15px;
+ }
+
+ .products__cart-icon {
+ margin-left: 0;
+ }
+ }
+
+ .order {
+ padding: 20px;
+
+ .order__title {
+ font-size: 20px;
+ text-align: center;
+ }
+
+ .order__total {
+ text-align: center;
+ }
+
+ .form__radio-group {
+ flex-direction: column;
+ gap: 15px;
+ }
+
+ .form__radio-label {
+ flex: none;
+ justify-content: flex-start;
+ }
+
+ .promo {
+ flex-direction: column;
+ gap: 10px;
+
+ &__btn {
+ width: 100%;
+ padding: 12px;
+ }
+ }
+
+ .order-btn {
+ padding: 12px;
+ font-size: 16px;
+ }
+
+ .services {
+ flex-direction: column;
+ align-items: center;
+ }
+ }
+ }
+
+ .product-image-container { height: 200px; }
+ .product-card.tall .product-image-container,
+ .product-card.large .product-image-container { height: 250px; }
+
+ .profile-page-main {
+ .profile-container {
+ flex-direction: column;
+ min-height: auto;
+ max-width: 100%;
+ box-shadow: none;
+ }
+ .profile-left-col {
+ flex: none;
+ width: 100%;
+ height: 100px;
+ .flex-center();
+ padding: 0;
+ }
+ .profile-right-col {
+ flex: none;
+ width: 100%;
+ padding: 30px 20px;
+ }
+ .profile-form-block { max-width: 100%; }
+ }
+
+ .form__row { flex-direction: column; }
+ .form__input--half { flex: 0 0 100%; max-width: 100%; }
+ .services { flex-direction: column; align-items: center; }
+
+ .services-section {
+ padding: 40px 0;
+ }
+
+ .service-card {
+ padding: 30px 20px;
+ min-height: 180px;
+
+ &--green,
+ &--beige {
+ max-width: 100%;
+ }
+
+ &__title {
+ font-size: 20px;
+ }
+
+ &__text {
+ font-size: 14px;
+ }
+ }
+ .solutions-slider {
+ margin: 20px auto;
+ &__slide {
+ .solution-text-overlay {
+ top: 8%;
+ left: 4%;
+ h2 {
+ font-size: 20px;
+ margin-bottom: 3px;
+ line-height: 1.1;
+ }
+ p {
+ font-size: 15px;
+ line-height: 1.1;
+ }
+ }
+ .solution-image-link {
+ bottom: 90px;
+ padding: 8px 20px;
+ font-size: 13px;
+ }
+ }
+ }
+}
+
+// Стили для ошибок полей
+.error-input {
+ border-color: #ff4444 !important;
+ box-shadow: 0 0 0 1px #ff4444;
+}
+
+.field-error {
+ color: #ff4444;
+ font-size: 12px;
+ margin-top: 5px;
+ margin-bottom: 10px;
+}
+
+// Стили для сообщений
+.message {
+ padding: 15px;
+ margin: 20px 0;
+ border-radius: 5px;
+ display: none;
+}
+
+.message.error {
+ background-color: #ffebee;
+ color: #c62828;
+ border: 1px solid #ffcdd2;
+}
+
+.message.success {
+ background-color: #e8f5e9;
+ color: #2e7d32;
+ border: 1px solid #c8e6c9;
+}
+
+// Добавьте в конец файла
+.access-denied {
+ text-align: center;
+ padding: 80px 20px;
+ background: white;
+ border-radius: 10px;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+ margin: 50px 0;
+
+ h2 {
+ color: #dc3545;
+ margin-bottom: 30px;
+ font-size: 28px;
+ }
+
+ p {
+ color: #666;
+ margin-bottom: 40px;
+ font-size: 18px;
+ line-height: 1.6;
+ }
+
+ .btn {
+ margin: 5px;
+ min-width: 200px;
+ }
+}
+// =======================
+// === ПРОФИЛЬ ПОЛЬЗОВАТЕЛЯ ===
+// =======================
+
+.user-profile-dropdown {
+ position: relative;
+ display: inline-block;
+
+ &__toggle {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ cursor: pointer;
+ padding: 8px 12px;
+ border-radius: 4px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+ }
+
+ .user-avatar {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ background-color: @color-primary;
+ color: @color-text-light;
+ .flex-center();
+ font-weight: bold;
+ }
+
+ .user-info {
+ display: flex;
+ flex-direction: column;
+
+ .user-email {
+ font-size: 12px;
+ color: #666;
+ max-width: 150px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .user-status {
+ font-size: 10px;
+ padding: 2px 6px;
+ border-radius: 10px;
+ text-transform: uppercase;
+
+ &.admin {
+ background-color: #617365;
+ color: white;
+ }
+
+ &.user {
+ background-color: #28a745;
+ color: white;
+ }
+ }
+ }
+ }
+
+ &__menu {
+ .menu-base();
+ width: 220px;
+ top: 100%;
+ right: 0;
+
+ .user-details {
+ padding: 15px;
+ border-bottom: 1px solid #eee;
+
+ .user-name {
+ font-weight: bold;
+ margin-bottom: 5px;
+ }
+
+ .user-registered {
+ font-size: 11px;
+ color: #999;
+ }
+ }
+
+ ul {
+ padding: 10px 0;
+
+ li {
+ padding: 8px 15px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ transition: background-color 0.3s ease;
+
+ &:hover {
+ background-color: #f5f5f5;
+ }
+
+ &.logout {
+ color: #dc3545;
+ border-top: 1px solid #eee;
+ margin-top: 5px;
+ padding-top: 12px;
+
+ &:hover {
+ background-color: #ffe6e6;
+ }
+ }
+ }
+ }
+ }
+
+ &:hover &__menu {
+ display: block;
+ }
+}
+
+// =======================
+// === КАРТОЧКА ТОВАРА ===
+// =======================
+
+.product-image-container {
+ position: relative;
+ overflow: hidden;
+ margin-bottom: 0;
+ padding: 0;
+ height: 250px;
+ .flex-center();
+
+ &:hover {
+ .product-overlay-info {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+}
+
+.product-overlay-info {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
+ color: white;
+ padding: 15px;
+ opacity: 0;
+ transform: translateY(10px);
+ transition: all 0.3s ease;
+
+ .product-overlay-name {
+ font-weight: bold;
+ font-size: 14px;
+ margin-bottom: 5px;
+ }
+
+ .product-overlay-price {
+ font-size: 16px;
+ font-weight: bold;
+
+ .old-price {
+ text-decoration: line-through;
+ font-size: 12px;
+ color: #ccc;
+ margin-right: 5px;
+ }
+
+ .current-price {
+ color: #ffd700;
+ }
+ }
+
+ .product-overlay-category {
+ font-size: 11px;
+ opacity: 0.8;
+ margin-top: 3px;
+ }
+
+ .product-overlay-stock {
+ font-size: 11px;
+ margin-top: 5px;
+
+ &.out-of-stock {
+ color: #ff6b6b;
+ }
+
+ i {
+ margin-right: 5px;
+ }
+ }
+}
+
+.product-card-details {
+ padding: 15px;
+ background: white;
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+
+ .product-card-name {
+ font-weight: bold;
+ font-size: 16px;
+ margin-bottom: 8px;
+ color: @color-text-dark;
+ }
+
+ .product-card-description {
+ font-size: 13px;
+ color: #777;
+ margin-bottom: 10px;
+ flex-grow: 1;
+ }
+
+ .product-card-attributes {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-bottom: 10px;
+
+ .attribute {
+ font-size: 11px;
+ background: #f5f5f5;
+ padding: 3px 8px;
+ border-radius: 12px;
+ color: #666;
+
+ i {
+ margin-right: 3px;
+ }
+ }
+ }
+
+ .product-card-price {
+ margin-bottom: 10px;
+
+ .old-price {
+ text-decoration: line-through;
+ font-size: 14px;
+ color: #999;
+ margin-right: 8px;
+ }
+
+ .current-price {
+ font-size: 18px;
+ font-weight: bold;
+ color: @color-button;
+ }
+ }
+
+ .add-to-cart-btn {
+ width: 100%;
+ padding: 8px;
+ font-size: 14px;
+ }
+
+ .admin-actions {
+ display: flex;
+ gap: 5px;
+ margin-top: 10px;
+
+ .admin-btn {
+ flex: 1;
+ font-size: 12px;
+ padding: 6px;
+
+ &.delete-btn {
+ background: #dc3545;
+
+ &:hover {
+ background: #c82333;
+ }
+ }
+ }
+ }
+}
+
+// =======================
+// === ПРОФИЛЬ ПОЛЬЗОВАТЕЛЯ ===
+// =======================
+
+.user-profile-dropdown {
+ position: relative;
+ display: inline-block;
+
+ .user-profile-toggle {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ cursor: pointer;
+ padding: 8px 12px;
+ border-radius: 4px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+
+ .dropdown-arrow {
+ transform: rotate(180deg);
+ }
+ }
+
+ .user-avatar {
+ width: 36px;
+ height: 36px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #617365 0%, #453227 100%);
+ color: @color-text-light;
+ .flex-center();
+ font-weight: bold;
+ font-size: 16px;
+ box-shadow: 0 2px 5px rgba(0,0,0,0.2);
+ }
+
+ .user-info {
+ display: flex;
+ flex-direction: column;
+
+ .user-email {
+ font-size: 12px;
+ color: #666;
+ max-width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .user-status {
+ font-size: 10px;
+ padding: 2px 8px;
+ border-radius: 12px;
+ text-transform: uppercase;
+ font-weight: bold;
+ text-align: center;
+ margin-top: 2px;
+
+ &.admin {
+ background-color: #617365;
+ color: white;
+ border: 1px solid #617365;
+ }
+
+ &.user {
+ background-color: #28a745;
+ color: white;
+ border: 1px solid #28a745;
+ }
+ }
+ }
+
+ .dropdown-arrow {
+ font-size: 10px;
+ color: #666;
+ transition: transform 0.3s ease;
+ }
+ }
+
+ .user-profile-menu {
+ .menu-base();
+ width: 280px;
+ top: 100%;
+ right: 0;
+ margin-top: 10px;
+ padding: 0;
+ overflow: hidden;
+
+ .user-profile-header {
+ padding: 20px;
+ background: linear-gradient(135deg, #617365 0%, #453227 100%);
+ color: white;
+
+ .user-profile-name {
+ font-weight: bold;
+ margin-bottom: 8px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 16px;
+ }
+
+ .user-profile-details {
+ small {
+ display: block;
+ opacity: 0.8;
+ margin-bottom: 5px;
+ font-size: 11px;
+
+ i {
+ margin-right: 5px;
+ width: 14px;
+ text-align: center;
+ }
+ }
+ }
+ }
+
+ .user-profile-links {
+ list-style: none;
+ padding: 10px 0;
+
+ li {
+ border-bottom: 1px solid #f0f0f0;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ a {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 20px;
+ color: #333;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: #f8f9fa;
+ color: @color-primary;
+ text-decoration: none;
+
+ i {
+ transform: scale(1.1);
+ }
+ }
+
+ i {
+ width: 20px;
+ text-align: center;
+ font-size: 14px;
+ color: #617365;
+ transition: transform 0.3s ease;
+ }
+
+ span {
+ flex-grow: 1;
+ }
+ }
+ }
+
+ .logout-item {
+ border-top: 2px solid #f0f0f0;
+ margin-top: 5px;
+
+ a {
+ color: #dc3545;
+
+ &:hover {
+ background-color: #ffe6e6;
+ color: #c82333;
+
+ i {
+ color: #dc3545;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ &:hover .user-profile-menu {
+ display: block;
+ animation: fadeIn 0.3s ease;
+ }
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+// Для мобильных устройств
+@media (max-width: 768px) {
+ .user-profile-dropdown {
+ .user-profile-toggle {
+ .user-info {
+ display: none;
+ }
+
+ .dropdown-arrow {
+ display: none;
+ }
+ }
+
+ .user-profile-menu {
+ width: 250px;
+ right: -50px;
+ }
+ }
+}
+// Добавьте в конец файла
+.unavailable-product {
+ position: relative;
+ opacity: 0.6;
+ filter: grayscale(0.7);
+
+ &::before {
+ content: "ТОВАР ЗАКОНЧИЛСЯ";
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background: rgba(0, 0, 0, 0.85);
+ color: white;
+ padding: 15px 25px;
+ border-radius: 5px;
+ font-weight: bold;
+ font-size: 16px;
+ text-align: center;
+ z-index: 100;
+ white-space: nowrap;
+ pointer-events: none;
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
+ }
+
+ .product-name-overlay {
+ .name, .price {
+ color: #999 !important;
+ text-shadow: none !important;
+ }
+ }
+
+ .add-to-cart-btn {
+ display: none !important;
+ }
+
+ &:hover {
+ transform: none !important;
+ cursor: not-allowed;
+ }
+}
+
+.out-of-stock-badge {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ background: #6c757d;
+ color: white;
+ padding: 5px 10px;
+ border-radius: 4px;
+ font-size: 12px;
+ font-weight: bold;
+ z-index: 10;
+}
+
+// Для админ-таблицы
+.admin-table tr.unavailable {
+ background-color: #f8f9fa !important;
+ opacity: 0.7;
+
+ td {
+ color: #999;
+ }
+}
+
+.status-unavailable {
+ background-color: #6c757d !important;
+ color: white !important;
+}
\ No newline at end of file
diff --git a/catalog_admin.php b/catalog_admin.php
deleted file mode 100644
index 524f499..0000000
--- a/catalog_admin.php
+++ /dev/null
@@ -1,924 +0,0 @@
-getConnection();
-
- // ОБРАБОТКА POST ЗАПРОСОВ ДЛЯ КАТЕГОРИЙ
- if ($_SERVER['REQUEST_METHOD'] === 'POST' && $is_admin) {
- $form_action = $_POST['action'] ?? '';
-
- if ($form_action === 'add_category' || $form_action === 'edit_category') {
- $name = trim($_POST['name'] ?? '');
- $parent_id = !empty($_POST['parent_id']) ? (int)$_POST['parent_id'] : null;
- $description = trim($_POST['description'] ?? '');
- $sort_order = (int)($_POST['sort_order'] ?? 0);
- $is_active = isset($_POST['is_active']) ? 1 : 0;
- $category_id_post = (int)($_POST['category_id'] ?? 0);
-
- // Валидация
- if (empty($name)) {
- $_SESSION['error'] = 'Название категории обязательно';
- header('Location: catalog_admin.php?action=' . $form_action . ($category_id_post ? '&id=' . $category_id_post : ''));
- exit();
- }
-
- // Создаем slug
- $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name));
- $slug = preg_replace('/^-+|-+$/', '', $slug); // Убираем дефисы по краям
-
- if ($form_action === 'add_category') {
- // Проверяем существование slug
- $check = $db->prepare("SELECT COUNT(*) FROM categories WHERE slug = ?");
- $check->execute([$slug]);
- if ($check->fetchColumn() > 0) {
- $slug = $slug . '-' . time(); // Добавляем timestamp для уникальности
- }
-
- $sql = "INSERT INTO categories (name, slug, parent_id, description, sort_order, is_active)
- VALUES (?, ?, ?, ?, ?, ?)";
- $stmt = $db->prepare($sql);
- $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active]);
-
- $_SESSION['message'] = 'Категория успешно добавлена';
- header('Location: catalog_admin.php?action=categories');
- exit();
-
- } elseif ($form_action === 'edit_category' && $category_id_post > 0) {
- // Проверяем существование slug для других категорий
- $check = $db->prepare("SELECT COUNT(*) FROM categories WHERE slug = ? AND category_id != ?");
- $check->execute([$slug, $category_id_post]);
- if ($check->fetchColumn() > 0) {
- $slug = $slug . '-' . $category_id_post;
- }
-
- $sql = "UPDATE categories SET
- name = ?, slug = ?, parent_id = ?, description = ?,
- sort_order = ?, is_active = ?, updated_at = CURRENT_TIMESTAMP
- WHERE category_id = ?";
- $stmt = $db->prepare($sql);
- $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active, $category_id_post]);
-
- $_SESSION['message'] = 'Категория успешно обновлена';
- header('Location: catalog_admin.php?action=categories');
- exit();
- }
- }
-
- // Удаление категории
- if ($form_action === 'delete_category') {
- $category_id_del = (int)($_POST['category_id'] ?? 0);
-
- if ($category_id_del > 0) {
- // Проверяем наличие активных товаров
- $check_products = $db->prepare("
- SELECT COUNT(*) as product_count
- FROM products
- WHERE category_id = ? AND is_available = TRUE
- ");
- $check_products->execute([$category_id_del]);
- $active_products = $check_products->fetchColumn();
-
- if ($active_products > 0) {
- $_SESSION['error'] = 'Невозможно удалить категорию с активными товарами';
- header('Location: catalog_admin.php?action=categories');
- exit();
- }
-
- // Проверяем дочерние категории
- $check_children = $db->prepare("
- SELECT COUNT(*) as child_count
- FROM categories
- WHERE parent_id = ? AND is_active = TRUE
- ");
- $check_children->execute([$category_id_del]);
- $active_children = $check_children->fetchColumn();
-
- if ($active_children > 0) {
- $_SESSION['error'] = 'Невозможно удалить категорию с активными дочерними категориями';
- header('Location: catalog_admin.php?action=categories');
- exit();
- }
-
- // Удаляем категорию
- $stmt = $db->prepare("DELETE FROM categories WHERE category_id = ?");
- $stmt->execute([$category_id_del]);
-
- $_SESSION['message'] = 'Категория успешно удалена';
- header('Location: catalog_admin.php?action=categories');
- exit();
- }
- }
- }
-
- // Получаем категории для отображения
- $categories_stmt = $db->query("
- SELECT c1.*, c2.name as parent_name,
- (SELECT COUNT(*) FROM products WHERE category_id = c1.category_id) as product_count
- FROM categories c1
- LEFT JOIN categories c2 ON c1.parent_id = c2.category_id
- ORDER BY c1.sort_order, c1.name
- ");
- $categories = $categories_stmt->fetchAll();
-
- // Для редактирования категории
- if ($action === 'edit_category' && $product_id > 0) {
- $cat_stmt = $db->prepare("SELECT * FROM categories WHERE category_id = ?");
- $cat_stmt->execute([$product_id]);
- $current_category = $cat_stmt->fetch();
-
- if (!$current_category) {
- $_SESSION['error'] = 'Категория не найдена';
- header('Location: catalog_admin.php?action=categories');
- exit();
- }
- }
-
- // Получаем товары
- $sql = "SELECT p.*, c.name as category_name FROM products p
- LEFT JOIN categories c ON p.category_id = c.category_id
- WHERE p.is_available = TRUE";
-
- $params = [];
- if ($category_id && is_numeric($category_id)) {
- $sql .= " AND p.category_id = ?";
- $params[] = $category_id;
- }
-
- $sql .= " ORDER BY p.product_id DESC";
-
- if ($params) {
- $stmt = $db->prepare($sql);
- $stmt->execute($params);
- } else {
- $stmt = $db->query($sql);
- }
-
- $products = $stmt->fetchAll();
-
- // Сообщения из сессии
- $message = $_SESSION['message'] ?? '';
- $error = $_SESSION['error'] ?? '';
-
- // Очищаем сообщения после использования
- unset($_SESSION['message']);
- unset($_SESSION['error']);
-
-} catch (PDOException $e) {
- $error = "Ошибка подключения к базе данных: " . $e->getMessage();
-}
-?>
-
-
-
-
-
-
- AETERNA - Каталог
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- = htmlspecialchars($message) ?>
-
-
-
-
-
- = htmlspecialchars($error) ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ID
- Название
- Родительская
- Товаров
- Порядок
- Статус
- Действия
-
-
-
-
-
- = $cat['category_id'] ?>
-
- = htmlspecialchars($cat['name']) ?>
- = htmlspecialchars($cat['slug']) ?>
-
- = htmlspecialchars($cat['parent_name'] ?? '—') ?>
-
- = $cat['product_count'] ?> товаров
-
- = $cat['sort_order'] ?>
-
-
- Активна
-
- Неактивна
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $product['price']): ?>
-
- -= round(($product['old_price'] - $product['price']) / $product['old_price'] * 100) ?>%
-
-
-
-
-
-
-
-
= htmlspecialchars($product['name']) ?>
-
- = htmlspecialchars(mb_substr($product['description'], 0, 100)) ?>...
-
-
- $product['price']): ?>
-
- = number_format($product['old_price'], 0, '', ' ') ?> ₽
-
-
- = number_format($product['price'], 0, '', ' ') ?> ₽
-
-
-
- В наличии: = $product['stock_quantity'] ?> шт.
-
-
-
- В корзину
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-getConnection();
-$action = $_POST['action'] ?? '';
-
-if ($_SERVER['REQUEST_METHOD'] === 'POST') {
- try {
- switch ($action) {
- case 'add_category':
- $name = $_POST['name'] ?? '';
- $parent_id = $_POST['parent_id'] ?: null;
- $description = $_POST['description'] ?? null;
- $sort_order = $_POST['sort_order'] ?? 0;
- $is_active = isset($_POST['is_active']) ? 1 : 0;
-
- // Создаем slug из названия
- $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name));
-
- $stmt = $db->prepare("
- INSERT INTO categories (name, slug, parent_id, description, sort_order, is_active)
- VALUES (?, ?, ?, ?, ?, ?)
- ");
-
- $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active]);
-
- header('Location: catalog_admin.php?action=categories&message=Категория успешно добавлена');
- exit();
-
- case 'edit_category':
- $category_id = $_POST['category_id'] ?? 0;
- $name = $_POST['name'] ?? '';
- $parent_id = $_POST['parent_id'] ?: null;
- $description = $_POST['description'] ?? null;
- $sort_order = $_POST['sort_order'] ?? 0;
- $is_active = isset($_POST['is_active']) ? 1 : 0;
-
- // Создаем slug из названия
- $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name));
-
- $stmt = $db->prepare("
- UPDATE categories SET
- name = ?,
- slug = ?,
- parent_id = ?,
- description = ?,
- sort_order = ?,
- is_active = ?
- WHERE category_id = ?
- ");
-
- $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active, $category_id]);
-
- header('Location: catalog_admin.php?action=categories&message=Категория успешно обновлена');
- exit();
-
- case 'delete_category':
- $category_id = $_POST['category_id'] ?? 0;
-
- // Проверяем, есть ли активные товары в этой категории
- $checkStmt = $db->prepare("
- SELECT COUNT(*)
- FROM products
- WHERE category_id = ? AND is_available = TRUE
- ");
- $checkStmt->execute([$category_id]);
- $active_products = $checkStmt->fetchColumn();
-
- if ($active_products > 0) {
- header('Location: catalog_admin.php?action=categories&error=Невозможно удалить категорию с активными товарами');
- exit();
- }
-
- // Проверяем дочерние категории
- $checkChildStmt = $db->prepare("
- SELECT COUNT(*)
- FROM categories
- WHERE parent_id = ? AND is_active = TRUE
- ");
- $checkChildStmt->execute([$category_id]);
- $active_children = $checkChildStmt->fetchColumn();
-
- if ($active_children > 0) {
- header('Location: catalog_admin.php?action=categories&error=Невозможно удалить категорию с активными дочерними категориями');
- exit();
- }
-
- // Удаляем категорию
- $stmt = $db->prepare("DELETE FROM categories WHERE category_id = ?");
- $stmt->execute([$category_id]);
-
- header('Location: catalog_admin.php?action=categories&message=Категория успешно удалена');
- exit();
- }
-
- } catch (PDOException $e) {
- header('Location: catalog_admin.php?action=categories&error=' . urlencode('Ошибка базы данных: ' . $e->getMessage()));
- exit();
- }
-}
-
-header('Location: catalog_admin.php');
-exit();
-?>
\ No newline at end of file
diff --git a/check_admin.php b/check_admin.php
deleted file mode 100644
index e64c585..0000000
--- a/check_admin.php
+++ /dev/null
@@ -1,17 +0,0 @@
-
\ No newline at end of file
diff --git a/check_auth_status.php b/check_auth_status.php
deleted file mode 100644
index 5ddf663..0000000
--- a/check_auth_status.php
+++ /dev/null
@@ -1,21 +0,0 @@
- isset($_SESSION['isLoggedIn']) && $_SESSION['isLoggedIn'] === true
-];
-
-if ($response['loggedIn']) {
- $response['user'] = [
- 'user_id' => $_SESSION['user_id'] ?? 0,
- 'email' => $_SESSION['user_email'] ?? '',
- 'full_name' => $_SESSION['full_name'] ?? '',
- 'is_admin' => $_SESSION['isAdmin'] ?? false,
- 'login_time' => $_SESSION['login_time'] ?? time()
- ];
-}
-
-header('Content-Type: application/json');
-echo json_encode($response);
-?>
\ No newline at end of file
diff --git a/check_categories_table.php b/check_categories_table.php
deleted file mode 100644
index 6fa72ca..0000000
--- a/check_categories_table.php
+++ /dev/null
@@ -1,51 +0,0 @@
-getConnection();
-
-echo "Проверка категорий в базе данных ";
-
-try {
- $stmt = $db->query("SELECT category_id, name, slug, parent_id FROM categories ORDER BY category_id");
- $categories = $stmt->fetchAll();
-
- if (empty($categories)) {
- echo "Категорий нет! Нужно сначала добавить категории.
";
-
- // Добавим тестовые категории
- $insert_sql = "
- INSERT INTO categories (name, slug, parent_id, description) VALUES
- ('Мягкая мебель', 'myagkaya-mebel', NULL, 'Диваны, кресла, пуфы'),
- ('Диваны', 'divany', 1, 'Прямые и угловые диваны'),
- ('Кресла', 'kresla', 1, 'Кресла для гостиной и офиса'),
- ('Спальня', 'spalnya', NULL, 'Кровати, тумбы, комоды'),
- ('Кровати', 'krovati', 4, 'Односпальные и двуспальные кровати')
- RETURNING category_id
- ";
-
- $db->exec($insert_sql);
- echo "Добавлены тестовые категории
";
-
- // Снова проверим
- $stmt = $db->query("SELECT category_id, name, slug, parent_id FROM categories ORDER BY category_id");
- $categories = $stmt->fetchAll();
- }
-
- echo "";
- echo "ID Название Slug Родитель ";
-
- foreach ($categories as $category) {
- echo "";
- echo "" . $category['category_id'] . " ";
- echo "" . htmlspecialchars($category['name']) . " ";
- echo "" . htmlspecialchars($category['slug']) . " ";
- echo "" . ($category['parent_id'] ?: '-') . " ";
- echo " ";
- }
-
- echo "
";
-
-} catch (PDOException $e) {
- echo "Ошибка: " . $e->getMessage();
-}
-?>
\ No newline at end of file
diff --git a/config/database.php b/config/database.php
index d7e632b..762cdec 100644
--- a/config/database.php
+++ b/config/database.php
@@ -7,9 +7,9 @@ class Database {
private function __construct() {
try {
$this->connection = new PDO(
- "pgsql:host=localhost;dbname=aeterna_db;",
- "postgres",
- "1234"
+ "pgsql:host=185.130.224.177;port=5481;dbname=postgres",
+ "admin",
+ "38feaad2840ccfda0e71243a6faaecfd"
);
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->connection->exec("SET NAMES 'utf8'");
diff --git a/debug_db.php b/debug_db.php
deleted file mode 100644
index 32ca002..0000000
--- a/debug_db.php
+++ /dev/null
@@ -1,55 +0,0 @@
-getConnection();
-
-echo "Проверка базы данных: ";
-
-// Проверка таблиц
-$tables = ['users', 'categories', 'products', 'orders', 'order_items', 'cart'];
-foreach ($tables as $table) {
- try {
- $result = $db->query("SELECT COUNT(*) FROM $table")->fetchColumn();
- echo "✅ Таблица '$table': $result записей ";
- } catch (Exception $e) {
- echo "❌ Таблица '$table': НЕ СУЩЕСТВУЕТ ";
- }
-}
-
-echo "Содержимое таблиц: ";
-
-// Показать категории
-echo "Категории: ";
-try {
- $categories = $db->query("SELECT * FROM categories")->fetchAll();
- if (empty($categories)) {
- echo "Категорий нет! ";
- } else {
- echo "ID Название Slug Родитель ";
- foreach ($categories as $cat) {
- echo "{$cat['category_id']} {$cat['name']} {$cat['slug']} {$cat['parent_id']} ";
- }
- echo "
";
- }
-} catch (Exception $e) {
- echo "Ошибка: " . $e->getMessage();
-}
-
-// Показать товары
-echo "Товары: ";
-try {
- $products = $db->query("SELECT * FROM products")->fetchAll();
- if (empty($products)) {
- echo "Товаров нет! ";
- } else {
- echo "ID Название Цена Категория Статус ";
- foreach ($products as $product) {
- echo "{$product['product_id']} {$product['name']} {$product['price']} {$product['category_id']} " . ($product['is_available'] ? 'Активен' : 'Неактивен') . " ";
- }
- echo "
";
- }
-} catch (Exception $e) {
- echo "Ошибка: " . $e->getMessage();
-}
-?>
\ No newline at end of file
diff --git a/fix_categories.php b/fix_categories.php
deleted file mode 100644
index 62503c1..0000000
--- a/fix_categories.php
+++ /dev/null
@@ -1,69 +0,0 @@
-getConnection();
-
-echo "Исправление проблем с категориями ";
-
-try {
- // 1. Удаляем категорию с ID=0 если она есть
- $db->exec("DELETE FROM categories WHERE category_id = 0");
-
- // 2. Проверяем, есть ли категории
- $catCount = $db->query("SELECT COUNT(*) FROM categories")->fetchColumn();
-
- if ($catCount == 0) {
- echo "Добавляем основные категории...
";
- $db->exec("
- INSERT INTO categories (name, slug, description, is_active) VALUES
- ('Диваны', 'divany', 'Мягкая мебель для гостиной', TRUE),
- ('Кресла', 'kresla', 'Кресла для гостиной и офиса', TRUE),
- ('Кровати', 'krovati', 'Мебель для спальни', TRUE),
- ('Столы', 'stoly', 'Обеденные и рабочие столы', TRUE),
- ('Стулья', 'stulya', 'Стулья для кухни и офиса', TRUE)
- ");
- echo "✓ Категории добавлены
";
- }
-
- // 3. Исправляем товары с category_id = 0 или NULL
- $badProducts = $db->query("
- SELECT COUNT(*) FROM products
- WHERE category_id IS NULL OR category_id = 0 OR
- category_id NOT IN (SELECT category_id FROM categories)
- ")->fetchColumn();
-
- if ($badProducts > 0) {
- echo "Исправляем товары с некорректными категориями ($badProducts шт)...
";
-
- // Получаем первую категорию
- $firstCat = $db->query("SELECT category_id FROM categories LIMIT 1")->fetchColumn();
-
- if ($firstCat) {
- $db->exec("
- UPDATE products
- SET category_id = $firstCat
- WHERE category_id IS NULL OR category_id = 0 OR
- category_id NOT IN (SELECT category_id FROM categories)
- ");
- echo "✓ Товары исправлены (category_id установлен в $firstCat)
";
- }
- }
-
- // 4. Показываем текущее состояние
- echo "Текущие категории: ";
- $cats = $db->query("SELECT category_id, name FROM categories ORDER BY category_id")->fetchAll();
-
- echo "";
- echo "ID Название ";
- foreach ($cats as $cat) {
- echo "{$cat['category_id']} {$cat['name']} ";
- }
- echo "
";
-
- echo "✓ База данных исправлена!
";
-
-} catch (PDOException $e) {
- echo "Ошибка: " . $e->getMessage() . "
";
-}
-?>
\ No newline at end of file
diff --git a/fix_database.php b/fix_database.php
deleted file mode 100644
index 9edc526..0000000
--- a/fix_database.php
+++ /dev/null
@@ -1,89 +0,0 @@
-getConnection();
-
-echo "Исправление проблем с базой данных ";
-
-try {
- // 1. Проверяем есть ли категории
- $stmt = $db->query("SELECT COUNT(*) FROM categories");
- $cat_count = $stmt->fetchColumn();
-
- if ($cat_count == 0) {
- echo "Добавляем тестовые категории...
";
- $db->exec("
- INSERT INTO categories (name, slug, description) VALUES
- ('Диваны', 'divany', 'Мягкая мебель для гостиной'),
- ('Кресла', 'kresla', 'Кресла для гостиной и офиса'),
- ('Кровати', 'krovati', 'Мебель для спальни')
- ");
- echo "✓ Категории добавлены
";
- }
-
- // 2. Проверяем товары с некорректными category_id
- $stmt = $db->query("
- SELECT COUNT(*) as bad_count
- FROM products
- WHERE category_id IS NULL OR category_id NOT IN (SELECT category_id FROM categories)
- ");
- $bad_count = $stmt->fetchColumn();
-
- if ($bad_count > 0) {
- echo "Исправляем товары с некорректными категориями ($bad_count шт)...
";
-
- // Устанавливаем первую доступную категорию
- $stmt = $db->query("SELECT category_id FROM categories LIMIT 1");
- $first_cat = $stmt->fetchColumn();
-
- if ($first_cat) {
- $db->exec("
- UPDATE products
- SET category_id = $first_cat
- WHERE category_id IS NULL OR category_id NOT IN (SELECT category_id FROM categories)
- ");
- echo "✓ Товары исправлены (установлена категория ID: $first_cat)
";
- }
- }
-
- // 3. Показываем текущее состояние
- echo "Текущее состояние: ";
-
- // Категории
- $stmt = $db->query("SELECT category_id, name FROM categories ORDER BY category_id");
- echo "Категории:
";
- while ($row = $stmt->fetch()) {
- echo "ID: {$row['category_id']} - {$row['name']} ";
- }
- echo " ";
-
- // Товары
- $stmt = $db->query("
- SELECT p.product_id, p.name, p.category_id, c.name as cat_name
- FROM products p
- LEFT JOIN categories c ON p.category_id = c.category_id
- ORDER BY p.product_id
- ");
-
- echo "Товары:
";
- echo "";
- echo "ID Название Категория ID Категория ";
-
- while ($row = $stmt->fetch()) {
- echo "";
- echo "{$row['product_id']} ";
- echo "" . htmlspecialchars($row['name']) . " ";
- echo "" . ($row['category_id'] ?: 'NULL') . " ";
- echo "" . ($row['cat_name'] ?: 'Без категории') . " ";
- echo " ";
- }
-
- echo "
";
-
- echo "✓ База данных исправлена!
";
-
-} catch (PDOException $e) {
- echo "Ошибка: " . $e->getMessage() . "
";
-}
-?>
\ No newline at end of file
diff --git a/header_common.php b/header_common.php
deleted file mode 100644
index 9b197d9..0000000
--- a/header_common.php
+++ /dev/null
@@ -1,142 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/image_upload.php b/image_upload.php
deleted file mode 100644
index b9833a9..0000000
--- a/image_upload.php
+++ /dev/null
@@ -1,53 +0,0 @@
- false, 'message' => 'Доступ запрещен']);
- exit();
-}
-
-if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['image'])) {
- $uploadDir = 'uploads/products/';
-
- // Создаем директорию если не существует
- if (!file_exists($uploadDir)) {
- mkdir($uploadDir, 0777, true);
- }
-
- $allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
- $maxSize = 5 * 1024 * 1024; // 5MB
-
- $file = $_FILES['image'];
-
- // Проверка типа файла
- if (!in_array($file['type'], $allowedTypes)) {
- echo json_encode(['success' => false, 'message' => 'Допустимые форматы: JPEG, PNG, GIF, WebP']);
- exit();
- }
-
- // Проверка размера
- if ($file['size'] > $maxSize) {
- echo json_encode(['success' => false, 'message' => 'Максимальный размер файла: 5MB']);
- exit();
- }
-
- // Генерируем уникальное имя
- $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
- $fileName = 'product_' . time() . '_' . rand(1000, 9999) . '.' . $extension;
- $filePath = $uploadDir . $fileName;
-
- if (move_uploaded_file($file['tmp_name'], $filePath)) {
- echo json_encode([
- 'success' => true,
- 'url' => $filePath,
- 'name' => $fileName
- ]);
- } else {
- echo json_encode(['success' => false, 'message' => 'Ошибка загрузки файла']);
- }
-} else {
- echo json_encode(['success' => false, 'message' => 'Файл не получен']);
-}
-?>
\ No newline at end of file
diff --git a/img b/img
new file mode 120000
index 0000000..14d6a13
--- /dev/null
+++ b/img
@@ -0,0 +1 @@
+assets/img
\ No newline at end of file
diff --git a/img/2_2.jpg b/img/2_2.jpg
deleted file mode 100644
index 1f9b783..0000000
Binary files a/img/2_2.jpg and /dev/null differ
diff --git a/img/3.jpg b/img/3.jpg
deleted file mode 100644
index 134dd4e..0000000
Binary files a/img/3.jpg and /dev/null differ
diff --git a/img/4.jpg b/img/4.jpg
deleted file mode 100644
index c462942..0000000
Binary files a/img/4.jpg and /dev/null differ
diff --git a/img/6.jpg b/img/6.jpg
deleted file mode 100644
index f94188c..0000000
Binary files a/img/6.jpg and /dev/null differ
diff --git a/img/7.jpg b/img/7.jpg
deleted file mode 100644
index 8ba2fe5..0000000
Binary files a/img/7.jpg and /dev/null differ
diff --git a/img/8.jpg b/img/8.jpg
deleted file mode 100644
index e869ff9..0000000
Binary files a/img/8.jpg and /dev/null differ
diff --git a/img/9.jpg b/img/9.jpg
deleted file mode 100644
index 967e002..0000000
Binary files a/img/9.jpg and /dev/null differ
diff --git a/img2 b/img2
new file mode 120000
index 0000000..14d6a13
--- /dev/null
+++ b/img2
@@ -0,0 +1 @@
+assets/img
\ No newline at end of file
diff --git a/includes/auth.php b/includes/auth.php
new file mode 100644
index 0000000..4c625ef
--- /dev/null
+++ b/includes/auth.php
@@ -0,0 +1,148 @@
+getConnection();
+
+ try {
+ $stmt = $db->prepare("
+ SELECT user_id, email, password_hash, full_name, phone, city, is_admin, is_active
+ FROM users WHERE email = ?
+ ");
+ $stmt->execute([$email]);
+ $user = $stmt->fetch();
+
+ if (!$user) {
+ return ['success' => false, 'message' => 'Пользователь не найден'];
+ }
+
+ if (!$user['is_active']) {
+ return ['success' => false, 'message' => 'Аккаунт заблокирован'];
+ }
+
+ if (!password_verify($password, $user['password_hash'])) {
+ return ['success' => false, 'message' => 'Неверный пароль'];
+ }
+
+ // Сохраняем в сессию
+ $_SESSION['user_id'] = $user['user_id'];
+ $_SESSION['user_email'] = $user['email'];
+ $_SESSION['full_name'] = $user['full_name'];
+ $_SESSION['user_phone'] = $user['phone'] ?? '';
+ $_SESSION['user_city'] = $user['city'] ?? '';
+ $_SESSION['isLoggedIn'] = true;
+ $_SESSION['isAdmin'] = (bool)$user['is_admin'];
+ $_SESSION['login_time'] = time();
+
+ // Обновляем время последнего входа
+ $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?");
+ $updateStmt->execute([$user['user_id']]);
+
+ return ['success' => true, 'user' => $user];
+
+ } catch (PDOException $e) {
+ return ['success' => false, 'message' => 'Ошибка базы данных'];
+ }
+}
+
+/**
+ * Регистрация нового пользователя
+ */
+function registerUser(array $data): array {
+ $db = Database::getInstance()->getConnection();
+
+ $email = trim($data['email'] ?? '');
+ $password = $data['password'] ?? '';
+ $fullName = trim($data['full_name'] ?? '');
+ $phone = trim($data['phone'] ?? '');
+ $city = trim($data['city'] ?? '');
+
+ // Валидация
+ if (empty($email) || empty($password) || empty($fullName)) {
+ return ['success' => false, 'message' => 'Заполните все обязательные поля'];
+ }
+
+ if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ return ['success' => false, 'message' => 'Некорректный email'];
+ }
+
+ if (strlen($password) < 6) {
+ return ['success' => false, 'message' => 'Пароль должен содержать минимум 6 символов'];
+ }
+
+ try {
+ // Проверяем существование пользователя
+ $checkStmt = $db->prepare("SELECT user_id FROM users WHERE email = ?");
+ $checkStmt->execute([$email]);
+
+ if ($checkStmt->fetch()) {
+ return ['success' => false, 'message' => 'Пользователь с таким email уже существует'];
+ }
+
+ // Создаем пользователя
+ $passwordHash = password_hash($password, PASSWORD_DEFAULT);
+
+ $stmt = $db->prepare("
+ INSERT INTO users (email, password_hash, full_name, phone, city, is_active)
+ VALUES (?, ?, ?, ?, ?, TRUE)
+ RETURNING user_id
+ ");
+ $stmt->execute([$email, $passwordHash, $fullName, $phone, $city]);
+ $userId = $stmt->fetchColumn();
+
+ // Автоматически авторизуем
+ $_SESSION['user_id'] = $userId;
+ $_SESSION['user_email'] = $email;
+ $_SESSION['full_name'] = $fullName;
+ $_SESSION['user_phone'] = $phone;
+ $_SESSION['user_city'] = $city;
+ $_SESSION['isLoggedIn'] = true;
+ $_SESSION['isAdmin'] = false;
+ $_SESSION['login_time'] = time();
+
+ return ['success' => true, 'user_id' => $userId];
+
+ } catch (PDOException $e) {
+ return ['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()];
+ }
+}
+
+/**
+ * Выход пользователя
+ */
+function logoutUser(): void {
+ $_SESSION = [];
+
+ if (ini_get("session.use_cookies")) {
+ $params = session_get_cookie_params();
+ setcookie(session_name(), '', time() - 42000,
+ $params["path"], $params["domain"],
+ $params["secure"], $params["httponly"]
+ );
+ }
+
+ session_destroy();
+}
+
+/**
+ * Проверка является ли пользователь администратором
+ */
+function checkAdminAccess(): bool {
+ if (!isset($_SESSION['isLoggedIn']) || $_SESSION['isLoggedIn'] !== true) {
+ return false;
+ }
+
+ if (!isset($_SESSION['isAdmin']) || $_SESSION['isAdmin'] !== true) {
+ return false;
+ }
+
+ return true;
+}
+
diff --git a/includes/footer.php b/includes/footer.php
new file mode 100644
index 0000000..439cf70
--- /dev/null
+++ b/includes/footer.php
@@ -0,0 +1,50 @@
+
+