LAB-06
353
labs/lab-06/dishes.js
Normal file
|
|
@ -0,0 +1,353 @@
|
||||||
|
const dishes = [
|
||||||
|
{
|
||||||
|
keyword: "mushroom-soup",
|
||||||
|
name: "Грибной крем-суп",
|
||||||
|
price: 280,
|
||||||
|
category: "soup",
|
||||||
|
count: "300 мл",
|
||||||
|
image: "img/soup/mushroom-soup.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "beet-soup",
|
||||||
|
name: "Традиционный борщ",
|
||||||
|
price: 240,
|
||||||
|
category: "soup",
|
||||||
|
count: "350 мл",
|
||||||
|
image: "img/soup/beet-soup.jpg",
|
||||||
|
kind: "meat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "chicken-noodle-soup",
|
||||||
|
name: "Куриный бульон с лапшой",
|
||||||
|
price: 220,
|
||||||
|
category: "soup",
|
||||||
|
count: "350 мл",
|
||||||
|
image: "img/soup/chicken-noodle-soup.jpg",
|
||||||
|
kind: "meat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "minestrone-soup",
|
||||||
|
name: "Итальянский суп минестроне",
|
||||||
|
price: 260,
|
||||||
|
category: "soup",
|
||||||
|
count: "350 мл",
|
||||||
|
image: "img/soup/minestrone-soup.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "tomato-soup",
|
||||||
|
name: "Томатный крем-суп",
|
||||||
|
price: 250,
|
||||||
|
category: "soup",
|
||||||
|
count: "300 мл",
|
||||||
|
image: "img/soup/tomato-soup.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "pumpkin-soup",
|
||||||
|
name: "Тыквенный суп с имбирем",
|
||||||
|
price: 270,
|
||||||
|
category: "soup",
|
||||||
|
count: "300 мл",
|
||||||
|
image: "img/soup/pumpkin-soup.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "fish-soup",
|
||||||
|
name: "Уха из лосося",
|
||||||
|
price: 320,
|
||||||
|
category: "soup",
|
||||||
|
count: "350 мл",
|
||||||
|
image: "img/soup/fish-soup.jpg",
|
||||||
|
kind: "fish"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "seafood-soup",
|
||||||
|
name: "Суп том-ям с морепродуктами",
|
||||||
|
price: 340,
|
||||||
|
category: "soup",
|
||||||
|
count: "350 мл",
|
||||||
|
image: "img/soup/seafood-soup.jpg",
|
||||||
|
kind: "fish"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "french-onion-soup",
|
||||||
|
name: "Французский луковый суп",
|
||||||
|
price: 300,
|
||||||
|
category: "soup",
|
||||||
|
count: "350 мл",
|
||||||
|
image: "img/soup/french-onion-soup.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "vegan-bowl-chickpeas",
|
||||||
|
name: "Веганский боул с нутом",
|
||||||
|
price: 390,
|
||||||
|
category: "main-course",
|
||||||
|
count: "350 г",
|
||||||
|
image: "img/main-dishes/vegan-bowl-chickpeas.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "grilled-chicken-vegetables",
|
||||||
|
name: "Куриная грудка с овощами гриль",
|
||||||
|
price: 450,
|
||||||
|
category: "main-course",
|
||||||
|
count: "350 г",
|
||||||
|
image: "img/main-dishes/grilled-chicken-vegetables.jpg",
|
||||||
|
kind: "meat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "salmon-quinoa-avocado",
|
||||||
|
name: "Лосось с киноа и авокадо",
|
||||||
|
price: 620,
|
||||||
|
category: "main-course",
|
||||||
|
count: "380 г",
|
||||||
|
image: "img/main-dishes/salmon-quinoa-avocado.jpg",
|
||||||
|
kind: "fish"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "seafood-pasta",
|
||||||
|
name: "Паста с морепродуктами",
|
||||||
|
price: 550,
|
||||||
|
category: "main-course",
|
||||||
|
count: "330 г",
|
||||||
|
image: "img/main-dishes/seafood-pasta.jpg",
|
||||||
|
kind: "fish"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "teriyaki-chicken-noodles",
|
||||||
|
name: "Рисовая лапша с курицей терияки",
|
||||||
|
price: 420,
|
||||||
|
category: "main-course",
|
||||||
|
count: "340 г",
|
||||||
|
image: "img/main-dishes/teriyaki-chicken-noodles.jpg",
|
||||||
|
kind: "meat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "beef-salad",
|
||||||
|
name: "Теплый салат с говядиной",
|
||||||
|
price: 490,
|
||||||
|
category: "main-course",
|
||||||
|
count: "320 г",
|
||||||
|
image: "img/main-dishes/beef-salad.jpg",
|
||||||
|
kind: "meat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "vegetable-stir-fry",
|
||||||
|
name: "Овощное рагу с тофу",
|
||||||
|
price: 380,
|
||||||
|
category: "main-course",
|
||||||
|
count: "350 г",
|
||||||
|
image: "img/main-dishes/vegetable-stir-fry.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "duck-orange-sauce",
|
||||||
|
name: "Утка в апельсиновом соусе",
|
||||||
|
price: 580,
|
||||||
|
category: "main-course",
|
||||||
|
count: "360 г",
|
||||||
|
image: "img/main-dishes/duck-orange-sauce.jpg",
|
||||||
|
kind: "meat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "mushroom-risotto",
|
||||||
|
name: "Ризотто с белыми грибами",
|
||||||
|
price: 410,
|
||||||
|
category: "main-course",
|
||||||
|
count: "340 г",
|
||||||
|
image: "img/main-dishes/mushroom-risotto.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "berry-juice",
|
||||||
|
name: "Ягодный морс",
|
||||||
|
price: 120,
|
||||||
|
category: "drink",
|
||||||
|
count: "300 мл",
|
||||||
|
image: "img/drinks/berry-juice.jpg",
|
||||||
|
kind: "cold"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "water",
|
||||||
|
name: "Минеральная вода",
|
||||||
|
price: 80,
|
||||||
|
category: "drink",
|
||||||
|
count: "500 мл",
|
||||||
|
image: "img/drinks/water.jpg",
|
||||||
|
kind: "cold"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "spinach-smoothie",
|
||||||
|
name: "Зеленый смузи с шпинатом",
|
||||||
|
price: 180,
|
||||||
|
category: "drink",
|
||||||
|
count: "350 мл",
|
||||||
|
image: "img/drinks/spinach-smoothie.jpg",
|
||||||
|
kind: "cold"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "ginger-lemonade",
|
||||||
|
name: "Имбирный лимонад",
|
||||||
|
price: 140,
|
||||||
|
category: "drink",
|
||||||
|
count: "300 мл",
|
||||||
|
image: "img/drinks/ginger-lemonade.jpg",
|
||||||
|
kind: "cold"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "mango-smoothie",
|
||||||
|
name: "Смузи манго-маракуйя",
|
||||||
|
price: 170,
|
||||||
|
category: "drink",
|
||||||
|
count: "350 мл",
|
||||||
|
image: "img/drinks/mango-smoothie.jpg",
|
||||||
|
kind: "cold"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "orange-juice",
|
||||||
|
name: "Свежевыжатый апельсиновый сок",
|
||||||
|
price: 150,
|
||||||
|
category: "drink",
|
||||||
|
count: "300 мл",
|
||||||
|
image: "img/drinks/orange-juice.jpg",
|
||||||
|
kind: "cold"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "cappuccino",
|
||||||
|
name: "Капучино",
|
||||||
|
price: 150,
|
||||||
|
category: "drink",
|
||||||
|
count: "300 мл",
|
||||||
|
image: "img/drinks/cappuccino.jpg",
|
||||||
|
kind: "hot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "green-tea",
|
||||||
|
name: "Зеленый чай",
|
||||||
|
price: 100,
|
||||||
|
category: "drink",
|
||||||
|
count: "400 мл",
|
||||||
|
image: "img/drinks/green-tea.jpg",
|
||||||
|
kind: "hot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "hot-chocolate",
|
||||||
|
name: "Горячий шоколад",
|
||||||
|
price: 160,
|
||||||
|
category: "drink",
|
||||||
|
count: "300 мл",
|
||||||
|
image: "img/drinks/hot-chocolate.jpg",
|
||||||
|
kind: "hot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "shrimp-salad",
|
||||||
|
name: "Салат с креветками и авокадо",
|
||||||
|
price: 380,
|
||||||
|
category: "salad",
|
||||||
|
count: "250 г",
|
||||||
|
image: "img/salads/shrimp-salad.jpg",
|
||||||
|
kind: "fish"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "caesar-salad",
|
||||||
|
name: "Цезарь с курицей",
|
||||||
|
price: 320,
|
||||||
|
category: "salad",
|
||||||
|
count: "280 г",
|
||||||
|
image: "img/salads/caesar-salad.jpg",
|
||||||
|
kind: "meat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "greek-salad",
|
||||||
|
name: "Греческий салат",
|
||||||
|
price: 280,
|
||||||
|
category: "salad",
|
||||||
|
count: "260 г",
|
||||||
|
image: "img/salads/greek-salad.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "caprese-salad",
|
||||||
|
name: "Капрезе с моцареллой",
|
||||||
|
price: 290,
|
||||||
|
category: "salad",
|
||||||
|
count: "240 г",
|
||||||
|
image: "img/salads/caprese-salad.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "quinoa-salad",
|
||||||
|
name: "Салат с киноа и овощами",
|
||||||
|
price: 310,
|
||||||
|
category: "salad",
|
||||||
|
count: "270 г",
|
||||||
|
image: "img/salads/quinoa-salad.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "beetroot-salad",
|
||||||
|
name: "Салат со свеклой и орехами",
|
||||||
|
price: 260,
|
||||||
|
category: "salad",
|
||||||
|
count: "250 г",
|
||||||
|
image: "img/salads/beetroot-salad.jpg",
|
||||||
|
kind: "veg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "chocolate-mousse",
|
||||||
|
name: "Шоколадный мусс",
|
||||||
|
price: 180,
|
||||||
|
category: "dessert",
|
||||||
|
count: "100 г",
|
||||||
|
image: "img/desserts/chocolate-mousse.jpg",
|
||||||
|
kind: "small"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "panna-cotta",
|
||||||
|
name: "Панна-котта с ягодным соусом",
|
||||||
|
price: 200,
|
||||||
|
category: "dessert",
|
||||||
|
count: "120 г",
|
||||||
|
image: "img/desserts/panna-cotta.jpg",
|
||||||
|
kind: "small"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "lemon-tart",
|
||||||
|
name: "Лимонный тарт",
|
||||||
|
price: 190,
|
||||||
|
category: "dessert",
|
||||||
|
count: "110 г",
|
||||||
|
image: "img/desserts/lemon-tart.jpg",
|
||||||
|
kind: "small"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "cheesecake",
|
||||||
|
name: "Чизкейк Нью-Йорк",
|
||||||
|
price: 280,
|
||||||
|
category: "dessert",
|
||||||
|
count: "150 г",
|
||||||
|
image: "img/desserts/cheesecake.jpg",
|
||||||
|
kind: "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "tiramisu",
|
||||||
|
name: "Тирамису классический",
|
||||||
|
price: 290,
|
||||||
|
category: "dessert",
|
||||||
|
count: "160 г",
|
||||||
|
image: "img/desserts/tiramisu.jpg",
|
||||||
|
kind: "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keyword: "chocolate-cake",
|
||||||
|
name: "Шоколадный торт",
|
||||||
|
price: 350,
|
||||||
|
category: "dessert",
|
||||||
|
count: "200 г",
|
||||||
|
image: "img/desserts/chocolate-cake.jpg",
|
||||||
|
kind: "large"
|
||||||
|
}
|
||||||
|
];
|
||||||
BIN
labs/lab-06/img/desserts/cheesecake.jpg
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
labs/lab-06/img/desserts/chocolate-cake.jpg
Normal file
|
After Width: | Height: | Size: 609 KiB |
BIN
labs/lab-06/img/desserts/chocolate-mousse.jpg
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
labs/lab-06/img/desserts/lemon-tart.jpg
Normal file
|
After Width: | Height: | Size: 410 KiB |
BIN
labs/lab-06/img/desserts/panna-cotta.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
labs/lab-06/img/desserts/tiramisu.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
labs/lab-06/img/drinks/berry-juice.jpg
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
labs/lab-06/img/drinks/cappuccino.jpg
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
labs/lab-06/img/drinks/ginger-lemonade.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
labs/lab-06/img/drinks/green-tea.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
labs/lab-06/img/drinks/hot-chocolate.jpg
Normal file
|
After Width: | Height: | Size: 298 KiB |
BIN
labs/lab-06/img/drinks/mango-smoothie.jpg
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
labs/lab-06/img/drinks/orange-juice.jpg
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
labs/lab-06/img/drinks/spinach-smoothie.jpg
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
labs/lab-06/img/drinks/water.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
labs/lab-06/img/main-dishes/beef-salad.jpg
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
labs/lab-06/img/main-dishes/duck-orange-sauce.jpg
Normal file
|
After Width: | Height: | Size: 804 KiB |
BIN
labs/lab-06/img/main-dishes/grilled-chicken-vegetables.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
labs/lab-06/img/main-dishes/mushroom-risotto.jpg
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
labs/lab-06/img/main-dishes/salmon-quinoa-avocado.jpg
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
labs/lab-06/img/main-dishes/seafood-pasta.jpg
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
labs/lab-06/img/main-dishes/teriyaki-chicken-noodles.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
labs/lab-06/img/main-dishes/vegan-bowl-chickpeas.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
labs/lab-06/img/main-dishes/vegetable-stir-fry.jpg
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
labs/lab-06/img/main.jpg
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
labs/lab-06/img/salads/beetroot-salad.jpg
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
labs/lab-06/img/salads/caesar-salad.jpg
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
labs/lab-06/img/salads/caprese-salad.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
labs/lab-06/img/salads/greek-salad.jpg
Normal file
|
After Width: | Height: | Size: 328 KiB |
BIN
labs/lab-06/img/salads/quinoa-salad.jpg
Normal file
|
After Width: | Height: | Size: 3.8 MiB |
BIN
labs/lab-06/img/salads/shrimp-salad.jpg
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
labs/lab-06/img/soup/beet-soup.jpg
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
labs/lab-06/img/soup/chicken-noodle-soup.jpg
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
labs/lab-06/img/soup/fish-soup.jpg
Normal file
|
After Width: | Height: | Size: 635 KiB |
BIN
labs/lab-06/img/soup/french-onion-soup.jpg
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
labs/lab-06/img/soup/minestrone-soup.jpg
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
labs/lab-06/img/soup/mushroom-soup.jpg
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
labs/lab-06/img/soup/pumpkin-soup.jpg
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
labs/lab-06/img/soup/seafood-soup.jpg
Normal file
|
After Width: | Height: | Size: 485 KiB |
BIN
labs/lab-06/img/soup/tomato-soup.jpg
Normal file
|
After Width: | Height: | Size: 69 KiB |
101
labs/lab-06/index.html
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="icon" href="https://deev.space/media/favicon.ico" type="image/x-icon">
|
||||||
|
<title>ЭкоЛанч - Доставка здоровых бизнес-ланчей в Москве</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>ЭкоЛанч</h1>
|
||||||
|
<nav>
|
||||||
|
<a href="index.html" id="active">Главная</a>
|
||||||
|
<a href="menu.html">Собрать ланч</a>
|
||||||
|
<a href="delivery.html">Доставка</a>
|
||||||
|
<a href="about.html">О нас</a>
|
||||||
|
<a href="#contacts">Контакты</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="about-company">
|
||||||
|
<h2>О компании ЭкоЛанч</h2>
|
||||||
|
<img src="img/main.jpg" alt="Здоровая еда в контейнерах">
|
||||||
|
<p>ЭкоЛанч - это современная компания по доставке здоровых бизнес-ланчей в офисы Москвы. Наша миссия - сделать правильное питание доступным для занятых людей, которые ценят свое время и здоровье.</p>
|
||||||
|
<p>Мы используем только свежие продукты от проверенных поставщиков, а наши повара готовят блюда каждое утро. Все ланчи упакованы в экологичную биоразлагаемую упаковку, потому что мы заботимся не только о вашем здоровье, но и о здоровье нашей планеты.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="advantages">
|
||||||
|
<h2>Наши преимущества</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Быстрая доставка в течение 60 минут по всей Москве в пределах МКАД</li>
|
||||||
|
<li>Свежие блюда, приготовленные утром из качественных продуктов</li>
|
||||||
|
<li>Сбалансированное меню, разработанное профессиональными диетологами</li>
|
||||||
|
<li>Экологичная упаковка, безопасная для окружающей среды</li>
|
||||||
|
<li>Гибкая система скидок для корпоративных клиентов и постоянных заказчиков</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="popular-dishes">
|
||||||
|
<h2>Самые популярные блюда</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Название блюда</th>
|
||||||
|
<th>Описание</th>
|
||||||
|
<th>Калорийность</th>
|
||||||
|
<th>Цена</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Куриная грудка с овощами гриль</td>
|
||||||
|
<td>Нежная куриная грудка с цукини, баклажанами и болгарским перцем</td>
|
||||||
|
<td>420 ккал</td>
|
||||||
|
<td>450 руб.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Лосось с киноа и авокадо</td>
|
||||||
|
<td>Запеченный лосось с гарниром из киноа и свежим авокадо</td>
|
||||||
|
<td>520 ккал</td>
|
||||||
|
<td>620 руб.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Теплый салат с говядиной</td>
|
||||||
|
<td>Сочная говядина с микс-салатом, томатами черри и кедровыми орешками</td>
|
||||||
|
<td>380 ккал</td>
|
||||||
|
<td>490 руб.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Веганский боул с нутом</td>
|
||||||
|
<td>Запеченный нут, хумус, овощи и тахини соус</td>
|
||||||
|
<td>450 ккал</td>
|
||||||
|
<td>390 руб.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Паста с морепродуктами</td>
|
||||||
|
<td>Паста из твердых сортов пшеницы с креветками, мидиями и томатным соусом</td>
|
||||||
|
<td>480 ккал</td>
|
||||||
|
<td>550 руб.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Рисовая лапша с курицей терияки</td>
|
||||||
|
<td>Рисовая лапша wok с куриным филе в соусе терияки и овощами</td>
|
||||||
|
<td>460 ккал</td>
|
||||||
|
<td>420 руб.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer id="contacts">
|
||||||
|
<p><b>Контактная информация</b></p>
|
||||||
|
<p>Телефон: <a href="tel:+79993737737">+7 (999) 373-77-37</a></p>
|
||||||
|
<p>Email: <a href="mailto:egor@deev.space">egor@deev.space</a></p>
|
||||||
|
<p>Адрес: г. Москва, ул. Михалковская, д. 7, к. 1, офис 813А</p>
|
||||||
|
<p>Режим работы: Пн-Пт с 8:00 до 20:00</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
246
labs/lab-06/menu.html
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="icon" href="https://deev.space/media/favicon.ico" type="image/x-icon">
|
||||||
|
<title>Собрать ланч - ЭкоЛанч</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>ЭкоЛанч</h1>
|
||||||
|
<nav>
|
||||||
|
<a href="index.html">Главная</a>
|
||||||
|
<a href="menu.html" id="active">Собрать ланч</a>
|
||||||
|
<a href="delivery.html">Доставка</a>
|
||||||
|
<a href="about.html">О нас</a>
|
||||||
|
<a href="#contacts">Контакты</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="combo-section">
|
||||||
|
<h2>Доступные для заказа варианты ланча</h2>
|
||||||
|
<div class="combo-grid">
|
||||||
|
<div class="combo-card">
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🍲</span>
|
||||||
|
<p>Суп</p>
|
||||||
|
</div>
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🍽️</span>
|
||||||
|
<p>Главное блюдо</p>
|
||||||
|
</div>
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🥗</span>
|
||||||
|
<p>Салат</p>
|
||||||
|
</div>
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🥤</span>
|
||||||
|
<p>Напиток</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="combo-card">
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🍲</span>
|
||||||
|
<p>Суп</p>
|
||||||
|
</div>
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🍽️</span>
|
||||||
|
<p>Главное блюдо</p>
|
||||||
|
</div>
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🥤</span>
|
||||||
|
<p>Напиток</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="combo-card">
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🍲</span>
|
||||||
|
<p>Суп</p>
|
||||||
|
</div>
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🥗</span>
|
||||||
|
<p>Салат</p>
|
||||||
|
</div>
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🥤</span>
|
||||||
|
<p>Напиток</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="combo-card">
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🍽️</span>
|
||||||
|
<p>Главное блюдо</p>
|
||||||
|
</div>
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🥗</span>
|
||||||
|
<p>Салат</p>
|
||||||
|
</div>
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🥤</span>
|
||||||
|
<p>Напиток</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="combo-card">
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🍽️</span>
|
||||||
|
<p>Главное блюдо</p>
|
||||||
|
</div>
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🥤</span>
|
||||||
|
<p>Напиток</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="combo-card combo-dessert">
|
||||||
|
<div class="combo-item">
|
||||||
|
<span class="combo-icon">🍰</span>
|
||||||
|
<p>Десерт</p>
|
||||||
|
</div>
|
||||||
|
<p class="combo-note-inline">(Можно добавить к любому заказу)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="combo-note">Десерты можно добавить к любому варианту ланча</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="section-header">
|
||||||
|
<h2>Супы</h2>
|
||||||
|
<div class="filter-buttons">
|
||||||
|
<button class="filter-btn" data-kind="fish">Рыбный</button>
|
||||||
|
<button class="filter-btn" data-kind="meat">Мясной</button>
|
||||||
|
<button class="filter-btn" data-kind="veg">Вегетарианский</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dishes-grid" id="soup-section"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="section-header">
|
||||||
|
<h2>Главные блюда</h2>
|
||||||
|
<div class="filter-buttons">
|
||||||
|
<button class="filter-btn" data-kind="fish">Рыбное</button>
|
||||||
|
<button class="filter-btn" data-kind="meat">Мясное</button>
|
||||||
|
<button class="filter-btn" data-kind="veg">Вегетарианское</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dishes-grid" id="main-course-section"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="section-header">
|
||||||
|
<h2>Салаты и стартеры</h2>
|
||||||
|
<div class="filter-buttons">
|
||||||
|
<button class="filter-btn" data-kind="fish">Рыбный</button>
|
||||||
|
<button class="filter-btn" data-kind="meat">Мясной</button>
|
||||||
|
<button class="filter-btn" data-kind="veg">Вегетарианский</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dishes-grid" id="salad-section"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="section-header">
|
||||||
|
<h2>Напитки</h2>
|
||||||
|
<div class="filter-buttons">
|
||||||
|
<button class="filter-btn" data-kind="cold">Холодный</button>
|
||||||
|
<button class="filter-btn" data-kind="hot">Горячий</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dishes-grid" id="drink-section"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="section-header">
|
||||||
|
<h2>Десерты</h2>
|
||||||
|
<div class="filter-buttons">
|
||||||
|
<button class="filter-btn" data-kind="small">Маленькая порция</button>
|
||||||
|
<button class="filter-btn" data-kind="medium">Средняя порция</button>
|
||||||
|
<button class="filter-btn" data-kind="large">Большая порция</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dishes-grid" id="dessert-section"></div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<section class="order-form">
|
||||||
|
<h2>Оформить заказ</h2>
|
||||||
|
<form id="order-form" action="https://httpbin.org/post" method="POST">
|
||||||
|
<div class="form-container">
|
||||||
|
|
||||||
|
<div class="order-section">
|
||||||
|
<h3>Ваш заказ</h3>
|
||||||
|
<div id="order-summary">
|
||||||
|
<p class="empty-order">Ничего не выбрано</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="customer-section">
|
||||||
|
<h3>Данные для доставки</h3>
|
||||||
|
|
||||||
|
<label for="name">Имя</label>
|
||||||
|
<input type="text" name="name" id="name" placeholder="Введите ваше имя" required>
|
||||||
|
|
||||||
|
<label for="email">Email</label>
|
||||||
|
<input type="email" name="email" id="email" placeholder="Введите ваш email" required>
|
||||||
|
|
||||||
|
<div class="checkbox-group">
|
||||||
|
<input type="checkbox" name="subscribe" id="subscribe" checked>
|
||||||
|
<label for="subscribe">Подписаться на рассылку</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="phone">Телефон</label>
|
||||||
|
<input type="tel" name="phone" id="phone" placeholder="Введите ваш телефон" required>
|
||||||
|
|
||||||
|
<label for="address">Адрес доставки</label>
|
||||||
|
<input type="text" name="address" id="address" placeholder="Введите адрес доставки" required>
|
||||||
|
<small class="form-hint">Доставка осуществляется только по Москве</small>
|
||||||
|
|
||||||
|
<div class="radio-group">
|
||||||
|
<label>Время доставки</label>
|
||||||
|
<div>
|
||||||
|
<input type="radio" name="delivery-time-type" id="asap" value="asap" required>
|
||||||
|
<label for="asap">Как можно скорее</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="radio" name="delivery-time-type" id="specific-time" value="specific-time" required>
|
||||||
|
<label for="specific-time">К определенному времени</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="delivery-time">Указать время</label>
|
||||||
|
<input type="time" name="delivery-time" id="delivery-time" min="07:00" max="23:00" step="300">
|
||||||
|
<small class="form-hint">Доступное время доставки с 7:00 до 23:00</small>
|
||||||
|
|
||||||
|
<label for="comment">Комментарий к заказу</label>
|
||||||
|
<textarea name="comment" id="comment" placeholder="Введите комментарий к заказу"></textarea>
|
||||||
|
|
||||||
|
<div class="form-buttons">
|
||||||
|
<button type="reset">Сбросить</button>
|
||||||
|
<button type="submit">Отправить заказ</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer id="contacts">
|
||||||
|
<p><b>Контактная информация</b></p>
|
||||||
|
<p>Телефон: <a href="tel:+79993737737">+7 (999) 373-77-37</a></p>
|
||||||
|
<p>Email: <a href="mailto:egor@deev.space">egor@deev.space</a></p>
|
||||||
|
<p>Адрес: г. Москва, ул. Михалковская, д. 7, к. 1, офис 813А</p>
|
||||||
|
<p>Режим работы: Пн-Пт с 8:00 до 20:00</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="dishes.js"></script>
|
||||||
|
<script src="menu.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
406
labs/lab-06/menu.js
Normal file
|
|
@ -0,0 +1,406 @@
|
||||||
|
const selectedDishes = {
|
||||||
|
soup: null,
|
||||||
|
'main-course': null,
|
||||||
|
salad: null,
|
||||||
|
drink: null,
|
||||||
|
dessert: null
|
||||||
|
};
|
||||||
|
|
||||||
|
let activeFilters = {
|
||||||
|
soup: null,
|
||||||
|
'main-course': null,
|
||||||
|
salad: null,
|
||||||
|
drink: null,
|
||||||
|
dessert: null
|
||||||
|
};
|
||||||
|
|
||||||
|
function sortDishes() {
|
||||||
|
dishes.sort(function(a, b) {
|
||||||
|
return a.name.localeCompare(b.name, 'ru');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayDishes() {
|
||||||
|
const soupSection = document.getElementById('soup-section');
|
||||||
|
const mainCourseSection = document.getElementById('main-course-section');
|
||||||
|
const saladSection = document.getElementById('salad-section');
|
||||||
|
const drinkSection = document.getElementById('drink-section');
|
||||||
|
const dessertSection = document.getElementById('dessert-section');
|
||||||
|
|
||||||
|
soupSection.innerHTML = '';
|
||||||
|
mainCourseSection.innerHTML = '';
|
||||||
|
saladSection.innerHTML = '';
|
||||||
|
drinkSection.innerHTML = '';
|
||||||
|
dessertSection.innerHTML = '';
|
||||||
|
|
||||||
|
dishes.forEach(function(dish) {
|
||||||
|
const dishCard = createDishCard(dish);
|
||||||
|
|
||||||
|
if (dish.category === 'soup') {
|
||||||
|
if (!activeFilters.soup || dish.kind === activeFilters.soup) {
|
||||||
|
soupSection.insertAdjacentHTML('beforeend', dishCard);
|
||||||
|
}
|
||||||
|
} else if (dish.category === 'main-course') {
|
||||||
|
if (!activeFilters['main-course'] ||
|
||||||
|
dish.kind === activeFilters['main-course']) {
|
||||||
|
mainCourseSection.insertAdjacentHTML('beforeend', dishCard);
|
||||||
|
}
|
||||||
|
} else if (dish.category === 'salad') {
|
||||||
|
if (!activeFilters.salad || dish.kind === activeFilters.salad) {
|
||||||
|
saladSection.insertAdjacentHTML('beforeend', dishCard);
|
||||||
|
}
|
||||||
|
} else if (dish.category === 'drink') {
|
||||||
|
if (!activeFilters.drink || dish.kind === activeFilters.drink) {
|
||||||
|
drinkSection.insertAdjacentHTML('beforeend', dishCard);
|
||||||
|
}
|
||||||
|
} else if (dish.category === 'dessert') {
|
||||||
|
if (!activeFilters.dessert ||
|
||||||
|
dish.kind === activeFilters.dessert) {
|
||||||
|
dessertSection.insertAdjacentHTML('beforeend', dishCard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addDishClickHandlers();
|
||||||
|
restoreSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDishCard(dish) {
|
||||||
|
return `
|
||||||
|
<div class="dish-card" data-dish="${dish.keyword}">
|
||||||
|
<img src="${dish.image}" alt="${dish.name}">
|
||||||
|
<p class="dish-price">${dish.price} руб.</p>
|
||||||
|
<p class="dish-name">${dish.name}</p>
|
||||||
|
<p class="dish-weight">${dish.count}</p>
|
||||||
|
<button>Добавить</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDishClickHandlers() {
|
||||||
|
const dishCards = document.querySelectorAll('.dish-card');
|
||||||
|
|
||||||
|
dishCards.forEach(function(card) {
|
||||||
|
card.addEventListener('click', function() {
|
||||||
|
const keyword = this.dataset.dish;
|
||||||
|
const dish = dishes.find(function(d) {
|
||||||
|
return d.keyword === keyword;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dish) {
|
||||||
|
selectDish(dish);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectDish(dish) {
|
||||||
|
const previousDish = selectedDishes[dish.category];
|
||||||
|
|
||||||
|
if (previousDish) {
|
||||||
|
const previousCard = document.querySelector(
|
||||||
|
`.dish-card[data-dish="${previousDish.keyword}"]`
|
||||||
|
);
|
||||||
|
if (previousCard) {
|
||||||
|
previousCard.classList.remove('selected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedDishes[dish.category] = dish;
|
||||||
|
|
||||||
|
const currentCard = document.querySelector(
|
||||||
|
`.dish-card[data-dish="${dish.keyword}"]`
|
||||||
|
);
|
||||||
|
if (currentCard) {
|
||||||
|
currentCard.classList.add('selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
updateOrderSummary();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateOrderSummary() {
|
||||||
|
const orderSummary = document.getElementById('order-summary');
|
||||||
|
const hasSelection = selectedDishes.soup ||
|
||||||
|
selectedDishes['main-course'] ||
|
||||||
|
selectedDishes.salad ||
|
||||||
|
selectedDishes.drink ||
|
||||||
|
selectedDishes.dessert;
|
||||||
|
|
||||||
|
if (!hasSelection) {
|
||||||
|
orderSummary.innerHTML = '<p class="empty-order">Ничего не выбрано</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let summaryHTML = '';
|
||||||
|
let totalPrice = 0;
|
||||||
|
|
||||||
|
if (selectedDishes.soup) {
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-category">
|
||||||
|
<h3>Суп</h3>
|
||||||
|
<div class="order-item">
|
||||||
|
<span>${selectedDishes.soup.name}</span>
|
||||||
|
<span>${selectedDishes.soup.price} руб.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
totalPrice += selectedDishes.soup.price;
|
||||||
|
} else {
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-category">
|
||||||
|
<h3>Суп</h3>
|
||||||
|
<p class="not-selected">Блюдо не выбрано</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedDishes['main-course']) {
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-category">
|
||||||
|
<h3>Главное блюдо</h3>
|
||||||
|
<div class="order-item">
|
||||||
|
<span>${selectedDishes['main-course'].name}</span>
|
||||||
|
<span>${selectedDishes['main-course'].price} руб.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
totalPrice += selectedDishes['main-course'].price;
|
||||||
|
} else {
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-category">
|
||||||
|
<h3>Главное блюдо</h3>
|
||||||
|
<p class="not-selected">Блюдо не выбрано</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedDishes.salad) {
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-category">
|
||||||
|
<h3>Салат</h3>
|
||||||
|
<div class="order-item">
|
||||||
|
<span>${selectedDishes.salad.name}</span>
|
||||||
|
<span>${selectedDishes.salad.price} руб.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
totalPrice += selectedDishes.salad.price;
|
||||||
|
} else {
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-category">
|
||||||
|
<h3>Салат</h3>
|
||||||
|
<p class="not-selected">Блюдо не выбрано</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedDishes.drink) {
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-category">
|
||||||
|
<h3>Напиток</h3>
|
||||||
|
<div class="order-item">
|
||||||
|
<span>${selectedDishes.drink.name}</span>
|
||||||
|
<span>${selectedDishes.drink.price} руб.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
totalPrice += selectedDishes.drink.price;
|
||||||
|
} else {
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-category">
|
||||||
|
<h3>Напиток</h3>
|
||||||
|
<p class="not-selected">Напиток не выбран</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedDishes.dessert) {
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-category">
|
||||||
|
<h3>Десерт</h3>
|
||||||
|
<div class="order-item">
|
||||||
|
<span>${selectedDishes.dessert.name}</span>
|
||||||
|
<span>${selectedDishes.dessert.price} руб.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
totalPrice += selectedDishes.dessert.price;
|
||||||
|
} else {
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-category">
|
||||||
|
<h3>Десерт</h3>
|
||||||
|
<p class="not-selected">Десерт не выбран</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
summaryHTML += `
|
||||||
|
<div class="order-total">
|
||||||
|
<h3>Стоимость заказа</h3>
|
||||||
|
<p class="total-price">${totalPrice} руб.</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
orderSummary.innerHTML = summaryHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupFilters() {
|
||||||
|
const filterButtons = document.querySelectorAll('.filter-btn');
|
||||||
|
|
||||||
|
filterButtons.forEach(function(button) {
|
||||||
|
button.addEventListener('click', function() {
|
||||||
|
const kind = this.dataset.kind;
|
||||||
|
const section = this.closest('section');
|
||||||
|
const category = section.querySelector('.dishes-grid').id
|
||||||
|
.replace('-section', '');
|
||||||
|
|
||||||
|
if (this.classList.contains('active')) {
|
||||||
|
this.classList.remove('active');
|
||||||
|
activeFilters[category] = null;
|
||||||
|
} else {
|
||||||
|
const sectionButtons = section
|
||||||
|
.querySelectorAll('.filter-btn');
|
||||||
|
sectionButtons.forEach(function(btn) {
|
||||||
|
btn.classList.remove('active');
|
||||||
|
});
|
||||||
|
this.classList.add('active');
|
||||||
|
activeFilters[category] = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayDishes();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValidCombo() {
|
||||||
|
const hasSoup = selectedDishes.soup !== null;
|
||||||
|
const hasMainCourse = selectedDishes['main-course'] !== null;
|
||||||
|
const hasSalad = selectedDishes.salad !== null;
|
||||||
|
const hasDrink = selectedDishes.drink !== null;
|
||||||
|
|
||||||
|
if (hasSoup && hasMainCourse && hasSalad && hasDrink) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSoup && hasMainCourse && hasDrink) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSoup && hasSalad && hasDrink) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasMainCourse && hasSalad && hasDrink) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasMainCourse && hasDrink) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValidationMessage() {
|
||||||
|
const hasSoup = selectedDishes.soup !== null;
|
||||||
|
const hasMainCourse = selectedDishes['main-course'] !== null;
|
||||||
|
const hasSalad = selectedDishes.salad !== null;
|
||||||
|
const hasDrink = selectedDishes.drink !== null;
|
||||||
|
|
||||||
|
if (!hasSoup && !hasMainCourse && !hasSalad && !hasDrink) {
|
||||||
|
return 'Ничего не выбрано. Выберите блюда для заказа';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasDrink) {
|
||||||
|
return 'Выберите напиток';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSoup && !hasMainCourse && !hasSalad) {
|
||||||
|
return 'Выберите главное блюдо/салат/стартер';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSalad && !hasSoup && !hasMainCourse) {
|
||||||
|
return 'Выберите суп или главное блюдо';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasMainCourse && !hasSoup && (hasDrink || selectedDishes.dessert)) {
|
||||||
|
return 'Выберите главное блюдо';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showNotification(message) {
|
||||||
|
const notification = document.createElement('div');
|
||||||
|
notification.classList.add('notification');
|
||||||
|
|
||||||
|
const messageText = document.createElement('p');
|
||||||
|
messageText.textContent = message;
|
||||||
|
|
||||||
|
const okButton = document.createElement('button');
|
||||||
|
okButton.textContent = 'Окей';
|
||||||
|
|
||||||
|
okButton.addEventListener('click', function() {
|
||||||
|
notification.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
notification.append(messageText);
|
||||||
|
notification.append(okButton);
|
||||||
|
|
||||||
|
document.body.append(notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupFormValidation() {
|
||||||
|
const orderForm = document.getElementById('order-form');
|
||||||
|
|
||||||
|
orderForm.addEventListener('submit', function(event) {
|
||||||
|
if (!isValidCombo()) {
|
||||||
|
event.preventDefault();
|
||||||
|
const message = getValidationMessage();
|
||||||
|
showNotification(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreSelection() {
|
||||||
|
Object.keys(selectedDishes).forEach(function(category) {
|
||||||
|
const dish = selectedDishes[category];
|
||||||
|
if (dish) {
|
||||||
|
const card = document.querySelector(
|
||||||
|
`.dish-card[data-dish="${dish.keyword}"]`
|
||||||
|
);
|
||||||
|
if (card) {
|
||||||
|
card.classList.add('selected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetSelection() {
|
||||||
|
Object.keys(selectedDishes).forEach(function(category) {
|
||||||
|
if (selectedDishes[category]) {
|
||||||
|
const card = document.querySelector(
|
||||||
|
`.dish-card[data-dish="${selectedDishes[category].keyword}"]`
|
||||||
|
);
|
||||||
|
if (card) {
|
||||||
|
card.classList.remove('selected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectedDishes[category] = null;
|
||||||
|
});
|
||||||
|
updateOrderSummary();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
sortDishes();
|
||||||
|
displayDishes();
|
||||||
|
setupFilters();
|
||||||
|
setupFormValidation();
|
||||||
|
|
||||||
|
const resetButton = document.querySelector('button[type="reset"]');
|
||||||
|
if (resetButton) {
|
||||||
|
resetButton.addEventListener('click', function() {
|
||||||
|
resetSelection();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
18
labs/lab-06/other/Вопросы для подготовки к защите ЛР №6.txt
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
Валидация форм
|
||||||
|
1. Для чего нужен метод preventDefault()?
|
||||||
|
|
||||||
|
2. Какие события связаны с формами и их элементами? В чём их отличия?
|
||||||
|
|
||||||
|
3. Что такое объект ValidityState и какие свойства он содержит?
|
||||||
|
|
||||||
|
4. Что позволяет задать метод setCustomValidity()?
|
||||||
|
|
||||||
|
5. Почему требуется проверять данные на стороне клиента?
|
||||||
|
|
||||||
|
6. Почему недостаточно проверять данные только на стороне клиента?
|
||||||
|
|
||||||
|
7. Как программно проверить валидность всей формы перед отправкой?
|
||||||
|
|
||||||
|
8. Какие события связаны непосредственно с процессом валидации?
|
||||||
|
|
||||||
|
9. Как программно отправить форму или сбросить её значения?
|
||||||
86
labs/lab-06/other/Задание - Лабораторная работа 6.md
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
# Лабораторная работа №6. Проверка данных на стороне клиента. Уведомления
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Добавьте блок с доступными для заказа вариантами ланча. Создайте скрипт, проверяющий состав ланча при отправке формы. Реализуйте показ уведомлений для пользователей.
|
||||||
|
|
||||||
|
## Порядок выполнения
|
||||||
|
|
||||||
|
Примерные макеты представлены ниже.
|
||||||
|
* Макет блока с доступными для заказа вариантами
|
||||||
|
* Макет уведомления
|
||||||
|
|
||||||
|
[Полный макет](https://lms.mospolytech.ru/pluginfile.php/1314144/mod_assign/intro/mockupfull.png "Полный макет") страницы:
|
||||||
|
|
||||||
|
1. Создайте блок с доступными для заказа вариантами ланча.
|
||||||
|
|
||||||
|
Структура блока:
|
||||||
|
|
||||||
|
- Заголовок
|
||||||
|
- Блок с вариантами (grid-контейнер, с 3 колонками на каждой строке)
|
||||||
|
- Блок каждого варианта ланча (flex-контейнер)
|
||||||
|
- Блок каждого блюда (flex-контейнер, направление главной оси - сверху вниз)
|
||||||
|
- Изображение блюда
|
||||||
|
- Подпись
|
||||||
|
|
||||||
|
Изображения с блюдами можно скачать [здесь](https://lms.mospolytech.ru/pluginfile.php/1314144/mod_assign/intro/icons.zip?time=1730060948701 "здесь").
|
||||||
|
|
||||||
|
Доступные для заказа варианты:
|
||||||
|
|
||||||
|
|1|2|3|4|5|
|
||||||
|
|---|---|---|---|---|
|
||||||
|
|Суп <br>Главное блюдо <br>Салат <br>Напиток|Суп <br>Главное блюдо <br>Напиток|Суп <br>Салат <br>Напиток|Главное блюдо <br>Салат <br>Напиток|Главное блюдо <br>Напиток|
|
||||||
|
|
||||||
|
В отдельном блоке необходимо разместить информацию о десертах. Их можно добавлять в любой вид ланча. Эту информацию нужно также отобразить на странице (поместить ниже подписи; шрифт меньше, чем у подписи на 2 пункта).
|
||||||
|
|
||||||
|
Измените свойства для изображений данного блока при наведении на них курсора. Используйте для этого transform с функциями трансформации translateY и scale.
|
||||||
|
|
||||||
|
На видео продемонстрирована работа transform:
|
||||||
|
|
||||||
|
2. Создайте скрипт, который будет проверять все ли необходимые блюда добавил пользователь.
|
||||||
|
|
||||||
|
Скрипт должен запускаться, когда пользователь отправляет форму. Пользователь может добавлять в заказ произвольные блюда. В итоге у него должен получиться один из вариантов ланчей, описанных выше. Если перечень выбранных блюд не соответствует ни одному из возможных вариантов (комбо), у пользователя не должно быть возможности оформить заказ (форма не должна отправляться), и на странице должно быть выведено уведомление с информацией о недостающих блюдах.
|
||||||
|
|
||||||
|
Существует 5 видов уведомлений:
|
||||||
|
|
||||||
|
|Текст уведомления|Когда выводится|Изображение|
|
||||||
|
|---|---|---|
|
||||||
|
|«Ничего не выбрано. Выберите блюда для заказа»|Не добавлено ни одно блюдо||
|
||||||
|
|«Выберите напиток»|Выбраны все необходимые блюда, кроме напитка||
|
||||||
|
|«Выберите главное блюдо/салат/стартер»|Выбран суп, но не выбраны главное блюдо/салат/стартер||
|
||||||
|
|«Выберите суп или главное блюдо»|Выбран салат/стартер, но не выбраны суп/главное блюдо||
|
||||||
|
|«Выберите главное блюдо»|Выбран напиток/десерт||
|
||||||
|
|
||||||
|
Уведомление должно создаваться динамически каждый раз, когда при попытке отправить форму скрипт обнаруживает, что какое-то блюдо не добавлено.
|
||||||
|
|
||||||
|
Оно должно отображаться поверх остальных элементов на странице и не менять положение при прокрутке. Также, его нужно отцентровать по вертикали и горизонтали.
|
||||||
|
При наведении на кнопку "Окей", изменяется цвет фона и текста кнопки.
|
||||||
|
При нажатии на кнопку, уведомление исчезает и удаляется со страницы.
|
||||||
|
На видео продемонстрирована работа уведомления:
|
||||||
|
|
||||||
|
### Материалы для изучения
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
[transform [Doka]](https://doka.guide/css/transform/)
|
||||||
|
[translateX() [MDN]](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateX)
|
||||||
|
[translateY() [MDN]](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateY)
|
||||||
|
[scale() [MDN]](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale)
|
||||||
|
[position [Doka]](https://doka.guide/css/position/)
|
||||||
|
[top, left, right, bottom [Doka]](https://doka.guide/css/top-left-right-bottom/)[](https://lms.mospolytech.ru/mod/assign/view.php?id=540007&forceview=1)
|
||||||
|
#### JS
|
||||||
|
[Отправка формы: событие и метод submit [JS.RU]](https://learn.javascript.ru/forms-submit)
|
||||||
|
[submit [Doka]](https://doka.guide/js/event-submit/)
|
||||||
|
[preventDefault() [Doka]](https://doka.guide/js/event-prevent-default/)
|
||||||
|
[preventDefault() [MDN]](https://developer.mozilla.org/ru/docs/Web/API/Event/preventDefault)
|
||||||
|
[Изменение документа [JS.RU]](https://learn.javascript.ru/modifying-document)
|
||||||
|
[document.createElement [MDN]](https://developer.mozilla.org/ru/docs/Web/API/Document/createElement)
|
||||||
|
[Создание элемента [JS.RU]](https://learn.javascript.ru/modifying-document#sozdanie-elementa
|
||||||
|
[Element.append() [MDN]](https://developer.mozilla.org/ru/docs/Web/API/Element/append)
|
||||||
|
[before() [MDN]](https://developer.mozilla.org/en-US/docs/Web/API/Element/before)
|
||||||
|
[after() [MDN]](https://developer.mozilla.org/en-US/docs/Web/API/Element/after)
|
||||||
|
[Методы вставки [JS.RU]](https://learn.javascript.ru/modifying-document#metody-vstavki)
|
||||||
|
[Element.remove() [MDN]](https://developer.mozilla.org/ru/docs/Web/API/Element/remove)
|
||||||
|
[Удаление узлов [JS.RU]](https://learn.javascript.ru/modifying-document#udalenie-uzlov)
|
||||||
|
#### Другое
|
||||||
|
[Юникод, внутреннее устройство строк](https://learn.javascript.ru/unicode)
|
||||||
|
[Emoji юникод](https://symbl.cc/ru/emoji/)
|
||||||
BIN
labs/lab-06/other/Результат запроса.png
Normal file
|
After Width: | Height: | Size: 186 KiB |
666
labs/lab-06/styles.css
Normal file
|
|
@ -0,0 +1,666 @@
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: #2d5016;
|
||||||
|
color: white;
|
||||||
|
padding: 20px 40px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
font-size: 36px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
margin: 0;
|
||||||
|
padding: 10px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: white;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a:hover {
|
||||||
|
color: #a8d08d;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a#active {
|
||||||
|
color: tomato;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 40px 60px;
|
||||||
|
max-width: 1200px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
margin: 0 0 50px 0;
|
||||||
|
padding: 30px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header h2 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 28px;
|
||||||
|
color: #2d5016;
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 400px;
|
||||||
|
object-fit: cover;
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 20px 0;
|
||||||
|
padding: 0 0 0 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
margin: 0 0 12px 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th {
|
||||||
|
background-color: #2d5016;
|
||||||
|
color: white;
|
||||||
|
padding: 15px;
|
||||||
|
text-align: left;
|
||||||
|
border: 1px solid #2d5016;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td {
|
||||||
|
padding: 12px 15px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr:nth-child(even) {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-section {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
background-color: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-dessert {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-icon {
|
||||||
|
font-size: 50px;
|
||||||
|
display: block;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-item:hover .combo-icon {
|
||||||
|
transform: translateY(-5px) scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-item p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-note-inline {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
margin: 0;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn {
|
||||||
|
background-color: white;
|
||||||
|
border: 2px solid #2d5016;
|
||||||
|
color: #2d5016;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn:hover {
|
||||||
|
background-color: #f1eee9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn.active {
|
||||||
|
background-color: #2d5016;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dishes-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dish-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 30px 40px;
|
||||||
|
border-radius: 35px;
|
||||||
|
cursor: pointer;
|
||||||
|
filter: drop-shadow(17px 19px 24px rgba(0, 0, 0, 0.13));
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dish-card.selected {
|
||||||
|
border: 3px solid #2d5016;
|
||||||
|
background-color: #f0f7ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dish-card.selected button {
|
||||||
|
background-color: #2d5016;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dish-card:hover {
|
||||||
|
border: 2px solid tomato;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dish-card:hover button {
|
||||||
|
background-color: tomato;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dish-card img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
aspect-ratio: 12 / 9;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 35px;
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dish-price {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dish-name {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dish-weight {
|
||||||
|
color: #888;
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dish-card button {
|
||||||
|
background-color: #f1eee9;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 30px;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-form {
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 40px 60px;
|
||||||
|
max-width: 1200px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-form h2 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#order-summary {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-order {
|
||||||
|
text-align: center;
|
||||||
|
color: #888;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-category {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-category h3 {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #2d5016;
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-item span:first-child {
|
||||||
|
font-weight: 600;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
max-width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-item span:last-child {
|
||||||
|
color: #2d5016;
|
||||||
|
font-weight: 600;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.not-selected {
|
||||||
|
color: #888;
|
||||||
|
font-style: italic;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-total {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 2px solid #2d5016;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-total h3 {
|
||||||
|
font-size: 22px;
|
||||||
|
color: #2d5016;
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-price {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #2d5016;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-section h3 {
|
||||||
|
font-size: 22px;
|
||||||
|
color: #2d5016;
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-section h3 {
|
||||||
|
font-size: 22px;
|
||||||
|
color: #2d5016;
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-form label {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-form select,
|
||||||
|
.order-form input[type="text"],
|
||||||
|
.order-form input[type="email"],
|
||||||
|
.order-form input[type="tel"],
|
||||||
|
.order-form input[type="time"],
|
||||||
|
.order-form textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 15px;
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-form select {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-form textarea {
|
||||||
|
height: 100px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group input[type="checkbox"] {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin: 0 10px 0 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group label {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 400;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-group {
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-group > label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-group > div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-group input[type="radio"] {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin: 0 10px 0 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-group input[type="radio"] + label {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 400;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-buttons button {
|
||||||
|
flex: 1;
|
||||||
|
padding: 15px 30px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-buttons button[type="reset"] {
|
||||||
|
background-color: #f1eee9;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-buttons button[type="reset"]:hover {
|
||||||
|
background-color: #e0ddd8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-buttons button[type="submit"] {
|
||||||
|
background-color: #2d5016;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-buttons button[type="submit"]:hover {
|
||||||
|
background-color: #3d6020;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-hint {
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
margin: -15px 0 20px 0;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background-color: white;
|
||||||
|
padding: 40px;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
|
||||||
|
z-index: 1000;
|
||||||
|
text-align: center;
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification p {
|
||||||
|
font-size: 18px;
|
||||||
|
margin: 0 0 25px 0;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification button {
|
||||||
|
background-color: #2d5016;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 40px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification button:hover {
|
||||||
|
background-color: white;
|
||||||
|
color: #2d5016;
|
||||||
|
border: 2px solid #2d5016;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
padding: 30px 60px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer p {
|
||||||
|
color: white;
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: white;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a:hover {
|
||||||
|
color: #a8d08d;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
.combo-grid {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dishes-grid {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-company img {
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section h2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dishes-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-company img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th,
|
||||||
|
table td {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-buttons {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification {
|
||||||
|
max-width: 90%;
|
||||||
|
padding: 30px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
table th,
|
||||||
|
table td {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||