ю
This commit is contained in:
6
.env.sample
Normal file
6
.env.sample
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Пример переменных окружения
|
||||||
|
# HOTEL777KEY - секретный API-ключ для доступа к /api/bookings
|
||||||
|
HOTEL777KEY=your-secret-api-key-here
|
||||||
|
|
||||||
|
# PORT можно переопределить при необходимости
|
||||||
|
# PORT=3000
|
||||||
29
README.md
Normal file
29
README.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
Hotel 777 - локальная веб-площадка на Node.js/Express
|
||||||
|
|
||||||
|
Стэк:
|
||||||
|
- Backend: Node.js + Express + sqlite3
|
||||||
|
- База данных: SQLite (data/bookings.db создаётся локально во время работы)
|
||||||
|
- Frontend: статические файлы в папке public (index.html, CSS, JS)
|
||||||
|
- Доп. пакет: sharp для конвертации изображений
|
||||||
|
|
||||||
|
Как запустить
|
||||||
|
- Установить переменную окружения HOTEL777KEY (API ключ). Можно добавить файл .env с примером: HOTEL777KEY=ваш-ключ
|
||||||
|
- Установить зависимости: npm install
|
||||||
|
- Запуск в продакшн-режиме: npm run start
|
||||||
|
- Для разработки: npm run dev (требуется nodemon, установлен как глобальная/локальная зависимость)
|
||||||
|
- Браузер: перейти к http://localhost:3000
|
||||||
|
|
||||||
|
API
|
||||||
|
- POST /api/bookings: сохраняет новую заявку бронирования (требуется заголовок x-api-key, равный значению HOTEL777KEY)
|
||||||
|
- GET /api/bookings: получить список заявок (требуется API-ключ в заголовке x-api-key)
|
||||||
|
- Формы отправки и frontend-логику можно найти в public/scripts.js и соответствующих модульках food.js, location.js, about.js
|
||||||
|
|
||||||
|
Файлы проекта
|
||||||
|
- package.json: зависимости и скрипты запуска
|
||||||
|
- server.js: основной Express-сервер
|
||||||
|
- public/: фронтенд-ресурсы (index.html, scripts.js, style.css, food.js, summer-cafe.js и т.д.)
|
||||||
|
- data/: база данных SQLite (создаётся при запуске)
|
||||||
|
|
||||||
|
Примечания
|
||||||
|
- Файл .gitignore содержит data, .env и node_modules
|
||||||
|
- В репозитории нет ключа API; создавайте файл .env.example и храните секреты отдельно
|
||||||
@@ -4,5 +4,9 @@
|
|||||||
"express": "^5.2.1",
|
"express": "^5.2.1",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"sqlite3": "^6.0.1"
|
"sqlite3": "^6.0.1"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server.js",
|
||||||
|
"dev": "nodemon server.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
73
public/food.js
Normal file
73
public/food.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// 食 block: Кухня загружается отдельно как блок на странице
|
||||||
|
function generateFoodHTML(lang) {
|
||||||
|
const t = (k) => (window.translations[lang] && window.translations[lang][k]) || k;
|
||||||
|
return `
|
||||||
|
<section>
|
||||||
|
<h2 class="section-title animate" data-i18n="food_title">${t('food_title')}</h2>
|
||||||
|
<div class="about-grid">
|
||||||
|
<div class="about-image-wrapper animate delay-1">
|
||||||
|
<img src="img/food.webp" alt="${t('food_subtitle')}" class="about-img" loading="lazy">
|
||||||
|
</div>
|
||||||
|
<div class="about-text animate delay-2">
|
||||||
|
<h3>${t('food_subtitle')}</h3>
|
||||||
|
<p>${t('food_text')}</p>
|
||||||
|
<div class="facts-grid food-features">
|
||||||
|
<div class="fact-card">
|
||||||
|
<div class="fact-icon">🍽️</div>
|
||||||
|
<div class="fact-text">${t('food_request')}</div>
|
||||||
|
</div>
|
||||||
|
<div class="fact-card">
|
||||||
|
<div class="fact-icon">👨🍳</div>
|
||||||
|
<div class="fact-text">${t('food_chef')}</div>
|
||||||
|
</div>
|
||||||
|
<div class="fact-card">
|
||||||
|
<div class="fact-icon">🕒</div>
|
||||||
|
<div class="fact-text">${t('food_breakfast')}</div>
|
||||||
|
</div>
|
||||||
|
<div class="fact-card">
|
||||||
|
<div class="fact-icon">🕒</div>
|
||||||
|
<div class="fact-text">${t('food_lunch')}</div>
|
||||||
|
</div>
|
||||||
|
<div class="fact-card">
|
||||||
|
<div class="fact-icon">🕒</div>
|
||||||
|
<div class="fact-text">${t('food_dinner')}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="food-note">📢 <em>${t('food_note')}</em></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFood(lang) {
|
||||||
|
const foodSection = document.getElementById('food');
|
||||||
|
if (!foodSection) return;
|
||||||
|
foodSection.innerHTML = generateFoodHTML(lang);
|
||||||
|
|
||||||
|
// Анимации на повторный вход
|
||||||
|
document.querySelectorAll('.animate').forEach(el => {
|
||||||
|
if (el.style.animationPlayState !== 'running') {
|
||||||
|
el.style.animationPlayState = 'paused';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFoodLanguage(lang) {
|
||||||
|
if (document.getElementById('food').innerHTML.trim() !== '') {
|
||||||
|
// обновляем тексты, если уже отрисован блок
|
||||||
|
const header = document.querySelector('#food .section-title');
|
||||||
|
if (header) header.innerHTML = window.translations[lang].food_title;
|
||||||
|
// Перерисуем контент для корректной подстановки
|
||||||
|
renderFood(lang);
|
||||||
|
} else {
|
||||||
|
renderFood(lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.updateFoodLanguage = updateFoodLanguage;
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const currentLang = localStorage.getItem('siteLang') || 'ru';
|
||||||
|
renderFood(currentLang);
|
||||||
|
});
|
||||||
BIN
public/img/summer-cafe.png
Normal file
BIN
public/img/summer-cafe.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 904 KiB |
BIN
public/img/summer-cafe.webp
Normal file
BIN
public/img/summer-cafe.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
@@ -3,7 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="description" content="Hotel 777 — отдых в Абхазии, Мгудзырхуа. Комфортные номера, пляж, домашняя кухня.">
|
<meta name="description" content="Hotel 777 — отдых в Абхазии, Мгудзырхуа. Отель у моря, пляж, домашняя кухня, летнее кафе, Gudauta и Золотой берег.">
|
||||||
|
<meta name="keywords" content="отдых в абхазии, отель, гудаута, золотой берег, абхазия отдых, пляж, кухня абхазская, жилье абхазия, Gudauta, Abkhazia, Hotel 777">
|
||||||
<title>Hotel 777 | Отдых в Абхазии</title>
|
<title>Hotel 777 | Отдых в Абхазии</title>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<link rel="icon" href="img/favicon.ico" type="image/x-icon">
|
<link rel="icon" href="img/favicon.ico" type="image/x-icon">
|
||||||
@@ -22,11 +23,11 @@
|
|||||||
<a href="#location" data-i18n="nav_location">Где мы</a>
|
<a href="#location" data-i18n="nav_location">Где мы</a>
|
||||||
<a href="#booking" data-i18n="nav_booking">Бронь</a>
|
<a href="#booking" data-i18n="nav_booking">Бронь</a>
|
||||||
</nav>
|
</nav>
|
||||||
<select id="langSwitch" class="lang-switch" aria-label="Выбор языка">
|
<select id="langSwitch" class="lang-switch" aria-label="Выбор языка">
|
||||||
<option value="ru">Русский</option>
|
<option value="ru" selected>Русский</option>
|
||||||
<option value="ab">Аҧсуа</option>
|
<option value="en">English</option>
|
||||||
<option value="en">English</option>
|
<option value="ab">Аҧсуа</option>
|
||||||
</select>
|
</select>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- Hero секция -->
|
<!-- Hero секция -->
|
||||||
@@ -39,43 +40,11 @@
|
|||||||
<!-- Секция "О нас" (динамически через about.js) -->
|
<!-- Секция "О нас" (динамически через about.js) -->
|
||||||
<section id="about" class="white-bg"></section>
|
<section id="about" class="white-bg"></section>
|
||||||
|
|
||||||
<!-- Секция "Кухня" (с карточками питания) -->
|
<!-- Кухня будет загружаться отдельным скриптом food.js -->
|
||||||
<section id="food">
|
<section id="food"></section>
|
||||||
<h2 class="section-title animate" data-i18n="food_title">Вкус Абхазии</h2>
|
|
||||||
<div class="about-grid">
|
<!-- Летнее кафе будет добавлено в будущем (фото можно вставить позже) -->
|
||||||
<div class="about-image-wrapper animate delay-1">
|
<section id="summer-cafe" class="white-bg"></section>
|
||||||
<img src="img/food.webp" alt="Абхазская кухня" class="about-img" loading="lazy">
|
|
||||||
</div>
|
|
||||||
<div class="about-text animate delay-2">
|
|
||||||
<h3 data-i18n="food_subtitle">Домашняя кухня из местных продуктов</h3>
|
|
||||||
<p data-i18n="food_text">Почувствуйте настоящее гостеприимство! Мы готовим из того, что выросло прямо здесь: свежайший сыр сулугуни, ароматная абыста, сочные овощи с грядки и домашнее вино.</p>
|
|
||||||
|
|
||||||
<div class="facts-grid food-features">
|
|
||||||
<div class="fact-card">
|
|
||||||
<div class="fact-icon">🍽️</div>
|
|
||||||
<div class="fact-text" data-i18n="food_request">Учитываем пожелания по питанию</div>
|
|
||||||
</div>
|
|
||||||
<div class="fact-card">
|
|
||||||
<div class="fact-icon">👨🍳</div>
|
|
||||||
<div class="fact-text" data-i18n="food_chef">Приготовим блюдо для Вас – спросите у шефа</div>
|
|
||||||
</div>
|
|
||||||
<div class="fact-card">
|
|
||||||
<div class="fact-icon">🕒</div>
|
|
||||||
<div class="fact-text" data-i18n="food_breakfast">Завтрак: с 8:30 до 10:00</div>
|
|
||||||
</div>
|
|
||||||
<div class="fact-card">
|
|
||||||
<div class="fact-icon">🕒</div>
|
|
||||||
<div class="fact-text" data-i18n="food_lunch">Обед: с 12:00 до 14:00</div>
|
|
||||||
</div>
|
|
||||||
<div class="fact-card">
|
|
||||||
<div class="fact-icon">🕒</div>
|
|
||||||
<div class="fact-text" data-i18n="food_dinner">Ужин: с 19:00 до 21:00</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="food-note" data-i18n="food_note">📢 <em>Сообщите администратору о любых предпочтениях при заселении – мы всё организуем!</em></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Секция "Где мы" (без карты, только указатель и города) -->
|
<!-- Секция "Где мы" (без карты, только указатель и города) -->
|
||||||
<section id="location" class="white-bg"></section>
|
<section id="location" class="white-bg"></section>
|
||||||
@@ -135,9 +104,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="scripts.js"></script>
|
<script src="scripts.js"></script>
|
||||||
<script src="about.js"></script>
|
<script src="about.js"></script>
|
||||||
<script src="location.js"></script>
|
<script src="location.js"></script>
|
||||||
<script src="hero-slideshow.js"></script>
|
<script src="hero-slideshow.js"></script>
|
||||||
</body>
|
<script src="food.js"></script>
|
||||||
</html>
|
<script src="summer-cafe.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ window.translations = {
|
|||||||
hero_btn: "Забронировать номер",
|
hero_btn: "Забронировать номер",
|
||||||
about_title: "Море в шаговой доступности",
|
about_title: "Море в шаговой доступности",
|
||||||
about_subtitle: "Бескрайние пляжи Гудауты",
|
about_subtitle: "Бескрайние пляжи Гудауты",
|
||||||
about_text: "Наш отель расположен в живописном селе Мгудзырхуа. Мы предлагаем комфортные номера и прямой выход к широкому, чистому галечно-песчаному пляжу.",
|
about_text: "Наш отель расположен в живописном селе Мгудзырхуа на берегу Черного моря. Мы предлагаем комфортные номера с современными удобствами, прямой выход к широкому галечно-песчаному пляжу и впечатляющие виды на Кавказские горы. В окрестностях можно прогуляться по историческим улочкам, попробовать свежие местные продукты и блюда абхазской кухни. Гости ценят спокойствие, уют и близость к природе; для семей предусмотрены удобства и развлечения на территории.",
|
||||||
about_extra: "Гудаутский район известен как «Золотой берег Абхазии» – здесь самые широкие пляжи, прогретое море и уникальный микроклимат, сочетающий горный и морской воздух.",
|
about_extra: "Гудаутский район известен как «Золотой берег Абхазии» – здесь самые широкие пляжи, прогретое море и уникальный микроклимат, сочетающий горный и морской воздух.",
|
||||||
fact1: "🏝️ Золотой берег Абхазии",
|
fact1: "🏝️ Золотой берег Абхазии",
|
||||||
fact2: "🌡️ Температура моря до +28°C летом",
|
fact2: "🌡️ Температура моря до +28°C летом",
|
||||||
@@ -89,7 +89,12 @@ window.translations = {
|
|||||||
"🏖️ Широкие галечные пляжи — одни из лучших в Абхазии.",
|
"🏖️ Широкие галечные пляжи — одни из лучших в Абхазии.",
|
||||||
"🍇 Традиционные виноградники и знаменитые сорта винограда."
|
"🍇 Традиционные виноградники и знаменитые сорта винограда."
|
||||||
],
|
],
|
||||||
loc_facts_default: "✨ Удивительные места ждут вас!"
|
loc_facts_default: "✨ Удивительные места ждут вас!",
|
||||||
|
summer_title: "Летнее кафе у моря",
|
||||||
|
summer_subtitle: "Свежие блюда и летний бриз",
|
||||||
|
summer_text: "Летнее кафе приглашает вас насладиться лёгкими блюдами на открытом воздухе. Экзотические фрукты, прохладительные напитки и тёплый морской воздух создают идеальный день у моря.",
|
||||||
|
summer_note: "Мы рекомендуем забронировать столик на закате; фотографии будут добавлены позже.",
|
||||||
|
summer_alt: "Летнее кафе у моря"
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
nav_about: "About Us",
|
nav_about: "About Us",
|
||||||
@@ -101,7 +106,7 @@ window.translations = {
|
|||||||
hero_btn: "Book a room",
|
hero_btn: "Book a room",
|
||||||
about_title: "Sea within walking distance",
|
about_title: "Sea within walking distance",
|
||||||
about_subtitle: "Endless beaches of Gudauta",
|
about_subtitle: "Endless beaches of Gudauta",
|
||||||
about_text: "Our hotel is located in the picturesque village of Mgudzyrkhua. We offer comfortable rooms and direct access to the wide, clean pebble-sand beach.",
|
about_text: "Our hotel is located in the picturesque village of Mgudzyrkhua on the shores of the Black Sea. We offer comfortable rooms with modern amenities, direct access to a wide pebble-sand beach, and stunning views of the Caucasus mountains. Nearby you can stroll historic streets, enjoy fresh local produce, and sample authentic Abkhaz cuisine. We welcome guests for short visits and extended stays with family-friendly services.",
|
||||||
about_extra: "The Gudauta district is known as the 'Golden Beach of Abkhazia' – the widest beaches, warm sea, and a unique microclimate combining mountain and sea air.",
|
about_extra: "The Gudauta district is known as the 'Golden Beach of Abkhazia' – the widest beaches, warm sea, and a unique microclimate combining mountain and sea air.",
|
||||||
fact1: "🏝️ Golden Beach of Abkhazia",
|
fact1: "🏝️ Golden Beach of Abkhazia",
|
||||||
fact2: "🌡️ Sea temperature up to +28°C in summer",
|
fact2: "🌡️ Sea temperature up to +28°C in summer",
|
||||||
@@ -180,7 +185,12 @@ window.translations = {
|
|||||||
"🏖️ Wide pebble beaches – some of the best in Abkhazia.",
|
"🏖️ Wide pebble beaches – some of the best in Abkhazia.",
|
||||||
"🍇 Traditional vineyards and famous grape varieties."
|
"🍇 Traditional vineyards and famous grape varieties."
|
||||||
],
|
],
|
||||||
loc_facts_default: "✨ Amazing places are waiting for you!"
|
loc_facts_default: "✨ Amazing places are waiting for you!",
|
||||||
|
summer_title: "Summer Café by the Sea",
|
||||||
|
summer_subtitle: "Fresh dishes and summer breeze",
|
||||||
|
summer_text: "The Summer Café invites you to enjoy light meals outdoors. Exotic fruits, cold drinks and the sea breeze create a perfect seaside day.",
|
||||||
|
summer_note: "We recommend reserving a table at sunset; photos will be added later.",
|
||||||
|
summer_alt: "Summer Café by the Sea"
|
||||||
},
|
},
|
||||||
ab: {
|
ab: {
|
||||||
nav_about: "Ҳара ҳхәыҷра",
|
nav_about: "Ҳара ҳхәыҷра",
|
||||||
@@ -301,7 +311,36 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
|
|
||||||
// Локализация основных элементов (с data-i18n)
|
// Локализация основных элементов (с data-i18n)
|
||||||
const langSelect = document.getElementById('langSwitch');
|
const langSelect = document.getElementById('langSwitch');
|
||||||
let currentLang = localStorage.getItem('siteLang') || 'ru';
|
// По умолчанию выбор — русский, затем английский, абхазский
|
||||||
|
let currentLang = localStorage.getItem('siteLang') || 'ru';
|
||||||
|
|
||||||
|
// Применить язык без перезагрузки страницы
|
||||||
|
function setLanguage(lang) {
|
||||||
|
if (!lang || !window.translations[lang]) return;
|
||||||
|
const previousLang = localStorage.getItem('siteLang');
|
||||||
|
localStorage.setItem('siteLang', lang);
|
||||||
|
|
||||||
|
// Обновление текстов на странице
|
||||||
|
document.querySelectorAll('[data-i18n]').forEach(el => {
|
||||||
|
const key = el.getAttribute('data-i18n');
|
||||||
|
if (window.translations[lang][key] !== undefined) el.innerHTML = window.translations[lang][key];
|
||||||
|
});
|
||||||
|
document.querySelectorAll('[data-i18n-ph]').forEach(el => {
|
||||||
|
const key = el.getAttribute('data-i18n-ph');
|
||||||
|
if (window.translations[lang][key] !== undefined) el.placeholder = window.translations[lang][key];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обновление модульных секций
|
||||||
|
if (typeof window.updateLocationLanguage === 'function') window.updateLocationLanguage(lang);
|
||||||
|
if (typeof window.updateAboutLanguage === 'function') window.updateAboutLanguage(lang);
|
||||||
|
if (typeof window.updateFoodLanguage === 'function') window.updateFoodLanguage(lang);
|
||||||
|
if (typeof window.updateSummerCafeLanguage === 'function') window.updateSummerCafeLanguage(lang);
|
||||||
|
|
||||||
|
// Принудительное полное обновление страницы при смене языка
|
||||||
|
if (previousLang && previousLang !== lang) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const updateText = (lang) => {
|
const updateText = (lang) => {
|
||||||
document.querySelectorAll('[data-i18n]').forEach(el => {
|
document.querySelectorAll('[data-i18n]').forEach(el => {
|
||||||
@@ -320,11 +359,19 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
if (typeof window.updateAboutLanguage === 'function') {
|
if (typeof window.updateAboutLanguage === 'function') {
|
||||||
window.updateAboutLanguage(lang);
|
window.updateAboutLanguage(lang);
|
||||||
}
|
}
|
||||||
|
if (typeof window.updateFoodLanguage === 'function') {
|
||||||
|
window.updateFoodLanguage(lang);
|
||||||
|
}
|
||||||
|
if (typeof window.updateSummerCafeLanguage === 'function') {
|
||||||
|
window.updateSummerCafeLanguage(lang);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
langSelect.value = currentLang;
|
langSelect.value = currentLang;
|
||||||
updateText(currentLang);
|
// Применяем язык на старте
|
||||||
langSelect.onchange = (e) => updateText(e.target.value);
|
setLanguage(currentLang);
|
||||||
|
// Обработчик смены языка без перезагрузки страницы
|
||||||
|
langSelect.onchange = (e) => setLanguage(e.target.value);
|
||||||
|
|
||||||
// Cookie
|
// Cookie
|
||||||
if (!localStorage.getItem('cookiesAccepted')) {
|
if (!localStorage.getItem('cookiesAccepted')) {
|
||||||
@@ -398,4 +445,4 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
if (e.target === modal) window.closeModal();
|
if (e.target === modal) window.closeModal();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
background: rgba(0, 18, 25, 0.95);
|
background: #ffffff;
|
||||||
color: var(--white);
|
color: #1f2937;
|
||||||
padding: 1rem 5%;
|
padding: 1rem 5%;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
@@ -37,8 +37,9 @@ header {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(6px);
|
||||||
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.2);
|
border-bottom: 1px solid #e5e7eb;
|
||||||
|
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
@@ -48,9 +49,9 @@ header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.lang-switch {
|
.lang-switch {
|
||||||
background: rgba(255, 255, 255, 0.1);
|
background: #fff;
|
||||||
color: var(--white);
|
color: #1f2937;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
border: 1px solid #d1d5db;
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -58,12 +59,12 @@ header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.lang-switch option {
|
.lang-switch option {
|
||||||
background: var(--dark);
|
color: #1f2937;
|
||||||
color: var(--white);
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav a {
|
nav a {
|
||||||
color: var(--white);
|
color: #1f2937;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
margin-left: clamp(10px, 2vw, 20px);
|
margin-left: clamp(10px, 2vw, 20px);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -557,4 +558,4 @@ footer {
|
|||||||
@keyframes waveRipple {
|
@keyframes waveRipple {
|
||||||
0% { transform: scale(0); opacity: 1; }
|
0% { transform: scale(0); opacity: 1; }
|
||||||
100% { transform: scale(4); opacity: 0; }
|
100% { transform: scale(4); opacity: 0; }
|
||||||
}
|
}
|
||||||
|
|||||||
37
public/summer-cafe.js
Normal file
37
public/summer-cafe.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Летнее кафе: блок на сайте с текстами на разных языках
|
||||||
|
function generateSummerCafeHTML(lang) {
|
||||||
|
const t = (k) => (window.translations[lang] && window.translations[lang][k]) || k;
|
||||||
|
return `
|
||||||
|
<section id="summer-cafe-section" class="summer-cafe">
|
||||||
|
<h2 class="section-title animate" data-i18n="summer_title">${t('summer_title')}</h2>
|
||||||
|
<div class="about-grid">
|
||||||
|
<div class="about-text animate delay-1">
|
||||||
|
<h3>${t('summer_subtitle')}</h3>
|
||||||
|
<p>${t('summer_text')}</p>
|
||||||
|
<p class="summer-note" style="font-style:italic;">${t('summer_note') || ''}</p>
|
||||||
|
</div>
|
||||||
|
<div class="about-image-wrapper animate delay-2">
|
||||||
|
<!-- Реальное фото летнего кафе -->
|
||||||
|
<img src="img/summer-cafe.webp" alt="${t('summer_alt') || 'Летнее кафе'}" class="about-img" loading="lazy">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSummerCafe(lang) {
|
||||||
|
const container = document.getElementById('summer-cafe');
|
||||||
|
if (!container) return;
|
||||||
|
container.innerHTML = generateSummerCafeHTML(lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSummerCafeLanguage(lang) {
|
||||||
|
renderSummerCafe(lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.updateSummerCafeLanguage = updateSummerCafeLanguage;
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const currentLang = localStorage.getItem('siteLang') || 'ru';
|
||||||
|
renderSummerCafe(currentLang);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user