init
All checks were successful
Deploy / build (push) Successful in 52s

This commit is contained in:
alsaze
2025-12-09 00:09:09 +03:00
parent 38becd5e9b
commit 1a8d15e547
72 changed files with 640 additions and 92 deletions

58
components/BaseFooter.vue Normal file
View File

@@ -0,0 +1,58 @@
<template>
<UFooter class="border-t border-gray-200 mt-10">
<div class="w-full max-w-7xl mx-auto py-10 px-4 grid grid-cols-1 md:grid-cols-3 gap-10 text-sm">
<div id="footer-contacts">
<h3 class="font-semibold text-base mb-3">
Контакты
</h3>
<ul class="space-y-2 opacity-80">
<li>
<span class="font-medium">Телефон:</span><br>
<a href="tel:+74951234567" class="hover:opacity-100 opacity-70">
+7 (495) 123-45-67
</a>
</li>
<li>
<span class="font-medium">Email:</span><br>
<a href="mailto:info@rental-concierge.com" class="hover:opacity-100 opacity-70">
info@rental-concierge.com
</a>
</li>
<li>
<span class="font-medium">Адрес:</span><br>
Москва, Тверская улица, 1
</li>
</ul>
</div>
<div>
<h3 class="font-semibold text-base mb-3">
Навигация
</h3>
<ul class="space-y-2 opacity-80">
<li><a href="/" class="hover:opacity-100 opacity-70">Главная</a></li>
<li><a href="/nedvizhimost" class="hover:opacity-100 opacity-70">Недвижимость</a></li>
<li><a href="/transport" class="hover:opacity-100 opacity-70">Авто</a></li>
</ul>
</div>
<div class="md:text-right opacity-70 flex flex-col justify-between">
<div class="text-lg font-bold">
Rental
</div>
<div class="mt-4 md:mt-0">
© {{ new Date().getFullYear() }} Rental.
Все права защищены.
</div>
</div>
</div>
</UFooter>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@@ -131,6 +131,7 @@
<script setup lang="ts">
const toast = useToast()
const route = useRoute()
const contacts = [
{
@@ -201,7 +202,10 @@ const [comment, commentAttrs] = defineField('comment')
const onSubmit = handleSubmit(async (values) => {
const res = await $fetch('/api/send_mail', {
method: 'POST',
body: values,
body: {
...values,
route: route.path,
},
})
if (res.ok) {

View File

@@ -1,6 +1,6 @@
<template>
<div id="variations" class="main-carousel">
<h2>Актуальные варианты</h2>
<h2>{{ title }}</h2>
<Swiper
:modules="[Navigation, Autoplay]"
@@ -16,16 +16,31 @@
1280: { slidesPerView: 5 },
}"
>
<SwiperSlide v-for="item in previewItems" :key="item.id" class="main-carousel__variant">
<NuxtLink :to="`/post/${item.id}`">
<img :src="item.previewImage.src" :alt="item.shortTitle">
<div class="main-carousel__type text-sm ">
{{ $t(item.type) }}
</div>
<p class="text-sm">
{{ item.shortTitle }}
</p>
</NuxtLink>
<SwiperSlide
v-for="slide in mixedSlides"
:key="slide.id"
class="main-carousel__variant"
>
<template v-if="!slide.isText">
<NuxtLink :to="`/post/${slide.id}`">
<img :src="slide.previewImage.src" :alt="slide.shortTitle">
<div class="main-carousel__type text-sm">
{{ $t(slide.type) }}
</div>
<p class="text-sm">
{{ slide.shortTitle }}
</p>
</NuxtLink>
</template>
<template v-else>
<NuxtLink
href="#contacts"
class="main-carousel__text-slide"
>
{{ slide.text }}
</NuxtLink>
</template>
</SwiperSlide>
</Swiper>
</div>
@@ -34,6 +49,7 @@
<script setup lang="ts">
import { Autoplay, Navigation } from 'swiper/modules'
import { Swiper, SwiperSlide } from 'swiper/vue'
import { computed } from 'vue'
import 'swiper/css'
import 'swiper/css/navigation'
@@ -46,7 +62,36 @@ interface PreviewItem {
}
}
defineProps<{ previewItems: PreviewItem[] }>()
const props = defineProps<{ title?: 'Актуальные варианты', previewItems: PreviewItem[] }>()
const mixedSlides = computed(() => {
const result: Array<
PreviewItem | { isText: true, text: string }
> = []
props.previewItems.forEach((item, index) => {
result.push(item)
const count = index + 1
if (count % 6 === 0) {
result.push({
isText: true,
text: 'Хочешь больше вариантов?',
})
return
}
if (count % 3 === 0) {
result.push({
isText: true,
text: 'Не нашёл подходящий вариант?',
})
}
})
return result
})
</script>
<style scoped lang="scss">
@@ -68,6 +113,19 @@ defineProps<{ previewItems: PreviewItem[] }>()
}
}
&__text-slide {
height: 300px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px;
background: #334155;
color: white;
padding: 16px;
text-align: center;
font-size: 18px;
}
&__type {
position: absolute;
top: 4px;

View File

@@ -5,7 +5,19 @@ export const useMock = () => {
id: 13242314,
title: 'Lexus LX: 2008 г., 5.7 л, Автомат, Бензиновая, Внедорожник',
shortTitle: 'Lexus LX',
description: 'Основные характеристики и детали по фото: - Кузов: полноразмерный SUV, черный металлик, оригинальный фирменный обвес, хромированная решетка радиатора Lexus, рейлинги на крыше, подножки. - Оптика: биксенон/LED фары с омывателями, противотуманные фары в переднем бампере. - Колеса: легкосплавные диски темного цвета, всесезонные шины. - Салон: бежняя перфорированная кожа, второй ряд с капитанскими креслами и широким центральным подлокотником/консолью, черные защитные чехлы на передних спинках, фирменные коврики, отдельные воздуховоды и блок управления климатом для задних пассажиров. - Оснащение и удобства: мультируль, электрорегулировки сидений, подогревы, много-зонный климат-контроль, тонировка, камера/датчики (по наличию на бампере), электропривод стекол и зеркал. - Экстерьерные элементы: повторители поворота в зеркалах, хром-молдинги, спойлер, антенна-плавник. - Полный привод, высокий дорожный просвет, мощный V8 (характерно для LX 570). Автомобиль с кыргызскими номерами (KG, регион 05) по фото. Стильный черный цвет, богатая комплектация, просторный комфортный салон для дальних поездок и города.',
description: 'Lexus LX 570 — легендарный премиальный внедорожник, созданный для тех, кто ценит мощь, статус и абсолютный комфорт.\n'
+ 'Автомобиль 2008 года в редком насыщенном чёрном металлике смотрится внушительно и современно. Фирменный кузовной обвес, хромированная решётка радиатора и аккуратные линии делают внешний вид солидным и дорогим.\n'
+ '\n'
+ 'Массивная оптика с биксеноном и LED-элементами, омывателями фар и противотуманками обеспечивает уверенное освещение в любое время суток. Темные легкосплавные диски и всесезонные шины дополняют образ настоящего вседорожного флагмана.\n'
+ '\n'
+ 'Салон — территория комфорта и роскоши.\n'
+ 'Бежевая перфорированная кожа, капитанские кресла второго ряда с широким подлокотником, фирменные коврики и аккуратные чехлы создают уют для всех пассажиров. Отдельная климат-зона для заднего ряда, воздуховоды, удобный мультируль, электроприводы сидений и подогревы делают поездки максимально комфортными как в городе, так и на дальние расстояния.\n'
+ '\n'
+ 'Техническая часть — мощь и уверенность на дороге.\n'
+ 'Под капотом — надёжный и проверенный временем 5.7-литровый бензиновый V8, отлично сочетающийся с плавным автоматом. Полный привод, высокий клиренс и грамотная геометрия позволяют Lexus LX уверенно чувствовать себя как на трассе, так и вне асфальта.\n'
+ '\n'
+ 'Автомобиль на кыргызских номерах (KG, регион 05) по фотографиям.\n'
+ 'Стильный, статусный, просторный и по-настоящему удобный внедорожник, который способен решить любые задачи — от семейных поездок до серьёзных путешествий.',
type: 'rent',
category: 'transport',
previewImage: {
@@ -36,7 +48,19 @@ export const useMock = () => {
id: 1314,
title: 'LexMercedes-Benz G-Class: 2022 г., 4 л, Автомат, Бензиновая, Внедорожник',
shortTitle: 'Lex Mercedes Benz G-Class',
description: 'Машина в наличии в Бишкеке🇰🇬 90 пробег 2022 год G$ Без вложений Без ДТП',
description: 'Mercedes-Benz G-Class 2022 — мощный и стильный внедорожник премиум-класса для настоящих ценителей роскоши и комфорта.\n'
+ 'Автомобиль в идеальном состоянии, с минимальным пробегом всего 90 км, полностью готов к эксплуатации без каких-либо вложений и без ДТП. Этот G-Class сочетает в себе легендарный дизайн и современные технологии, сохраняя фирменную квадратную форму кузова, узнаваемую по всему миру.\n'
+ '\n'
+ 'Экстерьер и оснащение:\n'
+ 'Элегантный черный (или любой другой) кузов привлекает внимание, а массивные колесные арки и фирменная решётка радиатора подчеркивают солидность автомобиля. LED-фары, повторители поворота, прочные защитные элементы и высокий дорожный просвет делают G-Class уверенным на любой дороге, будь то город или бездорожье.\n'
+ '\n'
+ 'Салон — это сочетание премиального комфорта и технологий:\n'
+ 'Продуманный интерьер с качественными материалами, кожаной отделкой и современными системами управления создаёт атмосферу уюта и статусности. Удобные сиденья с подогревом, мультируль, мультимедийная система и многочисленные функции безопасности обеспечивают максимальный комфорт и уверенность за рулём.\n'
+ '\n'
+ 'Техническая часть:\n'
+ 'Под капотом — мощный 4-литровый бензиновый двигатель в сочетании с автоматической коробкой передач. Полный привод и продуманная геометрия кузова гарантируют уверенное управление в любых условиях, а надёжность и долговечность делают G-Class отличным выбором как для города, так и для дальних поездок.\n'
+ '\n'
+ 'Автомобиль доступен в Бишкеке, готов к просмотру и тест-драйву. Идеальный вариант для тех, кто ищет премиальный внедорожник 2022 года, полностью исправный и готовый к эксплуатации без вложений.',
type: 'sale',
category: 'transport',
previewImage: {
@@ -63,37 +87,382 @@ export const useMock = () => {
},
],
},
// category: 'nedvizhimost',
{
id: 133423414,
title: 'Лофт с проектором — Руставели',
shortTitle: 'Лофт с проектором — Руставели',
description: 'Историческая стильная квартира с проектором в спальне, уютным балконом и неоновыми огнями:) Он расположен в 200-летнем здании культурного наследия, которое расположено в исторической части города, рядом с Тбилисской государственной консерваторией (по вечерам вы можете услышать живую музыку, сидя на балконе). В этом районе есть целые театры, музеи, пабы, рестораны и магазины. В нескольких минутах ходьбы от проспекта Руставели и площади Свободы, автобусной остановки/от аэропорта, двух станций метро.',
type: 'sale',
category: 'nedvizhimost',
coordinates: [44.770495496222274, 41.716244387476706],
address: 'Грузия, Тбилиси улица пушкина дом калатушкина квартира 10',
id: 1334523412314,
title: 'BMW X5: 2024 г., 3 л, Дизель, Кроссовер',
shortTitle: 'BMW X5: 2024 г',
description: 'BMW X5 xDrive30d (рестайлинг)\n'
+ 'Год:2024-11 месяц\n'
+ 'С нулевым пробег\n'
+ 'Кореец\n'
+ 'Машина в пути\n'
+ '\n'
+ 'Цена под ключ\n'
+ '\n'
+ 'Кузов и дизайн:\n'
+ '- Белый кроссовер класса SUV с фирменной решёткой «двойная ноздря» и агрессивным М-стилем бамперов\n'
+ '- Светодиодная оптика спереди и сзади, узкие ДХО, тёмные задние фонари\n'
+ '- Два выхлопных патрубка трапециевидной формы\n'
+ '- Большие легкосплавные диски спортивного дизайна\n'
+ '- Рельефные пороги, аэродинамические накладки, рейлинги на крыше\n'
+ '\n'
+ 'Надписи/комплектация по фото:\n'
+ '- xDrive30d — полный привод xDrive, дизельная версия\n'
+ '- М-пакет (M Sport): спортивные бамперы и колёса, чёрные глянцевые вставки\n'
+ '- Камеры/датчики в бамперах — подготовка под ассистенты и парктроник\n'
+ '\n'
+ 'Интерьер и технологии (по видимым элементам модели):\n'
+ '- Панорамное остекление лобового, мультимедийный дисплей, цифровая приборная панель\n'
+ '- Многофункциональный руль, премиальная отделка салона\n'
+ '- Система кругового обзора/парковочные ассистенты\n'
+ '- Климат-контроль, продвинутые системы безопасности и помощи водителю\n'
+ '\n'
+ 'Ключевые особенности:\n'
+ '- Полный привод для уверенного сцепления в любых условиях\n'
+ '- Мощный и экономичный дизель 30d\n'
+ '- Обновлённый внешний вид: акцент на спортивность и технологии\n'
+ '- Просторный салон и багажник, высокий уровень комфорта для семьи и дальних поездок',
type: 'rent',
category: 'transport',
previewImage: {
src: '/tbilisi_1.avif',
src: '/bmv_1.jpeg',
},
images: [
{
src: '/tbilisi_2.avif',
src: '/bmv_2.jpeg',
},
{
src: '/tbilisi_3.avif',
src: '/bmv_3.jpeg',
},
{
src: '/tbilisi_4.avif',
src: '/bmv_4.jpeg',
},
{
src: '/tbilisi_5.avif',
src: '/bmv_5.jpeg',
},
{
src: '/tbilisi_6.avif',
src: '/bmv_6.jpeg',
},
{
src: '/tbilisi_7.avif',
src: '/bmv_7.jpeg',
},
{
src: '/bmv_8.jpeg',
},
{
src: '/bmv_9.jpeg',
},
{
src: '/bmv_10.jpeg',
},
{
src: '/bmv_11.jpeg',
},
{
src: '/bmv_12.jpeg',
},
{
src: '/bmv_13.jpeg',
},
],
},
{
id: 84234175,
title: 'Mercedes-Benz Vito: 2017 г., 2.1 л, Автомат, Дизель, Минивэн',
shortTitle: 'Mercedes-Benz Vito',
description: 'Продаю Mercedes-Benz Vito Maxi Long, салон переделан под Maybach , рассматриваю вариант обмена с доплатой в обе стороны.\n'
+ '\n'
+ '🔻КОМПЛЕКТАЦИЯ\n'
+ '🔸Внешний вид обвес спойлер литые диски 🔸рейлинги\n'
+ '🔸багажник\n'
+ '\n'
+ '🔻САЛОН\n'
+ '🔸кожа\n'
+ '🔸шторки алькантара\n'
+ '\n'
+ '🔻МУЛЬТИМЕДИА\n'
+ '🔸DVD\n'
+ '🔸MP3\n'
+ '🔸USB\n'
+ '\n'
+ '🔻БЕЗОПАСНОСТЬ антиблокировочная система (ABS)\n'
+ '🔸антипробуксовочная система\n'
+ '🔸система курсовой устойчивости подушки 🔸безопасности парктроник\n'
+ '🔸камера заднего вида\n'
+ '\n'
+ '🔻 Опции\n'
+ 'полный электропакет\n'
+ '🔸кондиционер\n'
+ '🔸климат контроль\n'
+ '🔸подогрев передних сидений\n'
+ '🔸подогрев всех сидений ксенон\n'
+ '🔸омыватель фар\n'
+ '🔸пневмоподвеска\n'
+ '🔸память сидений\n'
+ '🔸датчик дождя\n'
+ '🔸бортовой компьютер\n'
+ '🔸корректор фар\n'
+ '🔸центральный замок\n'
+ '🔸вентиляция сидений\n'
+ '🔸светодиодные фары',
type: 'sale',
category: 'transport',
previewImage: {
src: '/vito_1.jpeg',
},
images: [
{
src: '/vito_2.jpeg',
},
{
src: '/vito_3.jpeg',
},
{
src: '/vito_4.jpeg',
},
{
src: '/vito_5.jpeg',
},
{
src: '/vito_6.jpeg',
},
{
src: '/vito_7.jpeg',
},
{
src: '/vito_8.jpeg',
},
{
src: '/vito_9.jpeg',
},
],
},
{
id: 949534289572345,
title: 'GMC Yukon: 2023 г., 3 л, Автомат, Дизель, Внедорожник',
shortTitle: 'GMC Yukon: 2023 г',
description: 'GMC Yukon XL (чёрный), полноразмерный 78местный SUV.\n'
+ '\n'
+ 'Кузов и экстерьер:\n'
+ '- Длинная колесная база XL, увеличенный багажный отсек.\n'
+ '- Чёрный пакет оформления: массивная решётка радиатора, тонированные элементы, чёрные 2022" легкосплавные диски.\n'
+ '- Светодиодная оптика спереди и сзади, ДХО.\n'
+ '- Рельсы на крыше, спойлер над задней дверью.\n'
+ '- Парктроники/датчики в бамперах, камера заднего вида (по размещению модуля).\n'
+ '\n'
+ 'Интерьер и удобства:\n'
+ '- 3 ряда сидений; трансформация салона для перевозки крупного багажа.\n'
+ '- Многочисленные USBпорты и разъёмы для пассажиров.\n'
+ '- Климат-контроль для переднего и заднего рядов, вентиляционные дефлекторы во всех зонах.\n'
+ '- Мультимедийная система с большим центральным экраном, поддержкой современных интерфейсов.\n'
+ '- Многофункциональный руль, кнопки управления на спицах.\n'
+ '- Электропакет стеклоподъёмников и зеркал, затемнённые стекла.\n'
+ '\n'
+ 'Техника и безопасность:\n'
+ '- Полноразмерное шасси, высокий клиренс.\n'
+ '- Вероятный V8 и автоматическая коробка передач.\n'
+ '- Система стабилизации, ABS, подушки безопасности по периметру.\n'
+ '- Круиз‑контроль, ассистенты парковки.\n'
+ '\n'
+ 'Особенности:\n'
+ '- Эффектный единый чёрный стиль (Black Edition/AT4/Denali Black — по комплектации), выразительный дизайн, акцент на комфорт дальних поездок и вместительность.',
type: 'rent',
category: 'transport',
previewImage: {
src: '/yukon_1.jpeg',
},
images: [
{
src: '/yukon_2.jpeg',
},
{
src: '/yukon_3.jpeg',
},
{
src: '/yukon_4.jpeg',
},
{
src: '/yukon_5.jpeg',
},
{
src: '/yukon_6.jpeg',
},
{
src: '/yukon_7.jpeg',
},
],
},
{
id: 834234,
title: 'BMW 7 series: 2023 г., 3 л, Автомат, Гибрид, Седан',
shortTitle: 'BMW 7 series: 2023 г',
description: '✨ BMW 7 Series 2023 воплощение современного роскошного седана\n'
+ '\n'
+ 'BMW 7 Series 2023 года — это автомобиль, созданный для тех, кто ценит абсолютный комфорт, передовые технологии и престиж в каждом движении. Новое поколение легендарного седана поднимает планку премиальности ещё выше, предлагая идеальный баланс между мощью, элегантностью и технологичным совершенством.\n'
+ '\n'
+ '🚀 Динамика и эффективность\n'
+ '\n'
+ 'Под капотом — 3-литровый гибридный силовой агрегат, который сочетает в себе фирменный характер BMW и экологичность современных технологий. Мощная тяга, мгновенный отклик и плавность работы создают чувство полного контроля и уверенности на любой дороге.\n'
+ 'Автоматическая коробка передач обеспечивает точные и мягкие переключения, делая каждую поездку максимально комфортной.\n'
+ '\n'
+ '🎩 Дизайн, который выделяет\n'
+ '\n'
+ 'Экстерьер седана — это гармония строгих линий, уверенной посадки и благородных пропорций. Увеличенная решётка радиатора, выразительная световая графика и выверенная аэродинамика создают образ автомобиля, который невозможно не заметить.\n'
+ 'BMW 7 Series выглядит солидно, статусно и современно — это идеальный выбор для тех, кто ценит престиж без излишней показности.\n'
+ '\n'
+ '💎 Интерьер класса люкс\n'
+ '\n'
+ 'Салон выполнен из премиальных материалов и предлагает максимальный уровень комфорта:\n'
+ '\n'
+ 'мягкие кожаные поверхности, приятные на ощупь;\n'
+ '\n'
+ 'продуманная эргономика для водителя и пассажиров;\n'
+ '\n'
+ 'атмосферная подсветка, создающая уют и ощущение персонального пространства;\n'
+ '\n'
+ 'современная мультимедийная система с интуитивным управлением и высочайшим качеством звука.\n'
+ '\n'
+ 'Каждая деталь продумана, чтобы вы чувствовали себя не просто в автомобиле — а в личном бизнес-классе.\n'
+ '\n'
+ '🛡 Передовые технологии и безопасность\n'
+ '\n'
+ 'BMW 7 Series 2023 оснащён новейшими системами помощи водителю: адаптивный круиз-контроль, удержание в полосе, предупреждение столкновений и множество других интеллектуальных функций делают поездки безопасными и заботятся о вас на каждом километре.\n'
+ '\n'
+ '🌍 Идеальный выбор для тех, кто хочет больше\n'
+ '\n'
+ 'Этот гибридный седан сочетает в себе комфорт представительского класса, динамику спортивного автомобиля и технологичность современного мира. BMW 7 Series — это не просто транспорт, а яркое отражение индивидуальности и сильного характера своего владельца.',
type: 'sale',
category: 'transport',
previewImage: {
src: '/sedan_1.jpeg',
},
images: [
{
src: '/sedan_2.jpeg',
},
{
src: '/sedan_3.jpeg',
},
{
src: '/sedan_4.jpeg',
},
{
src: '/sedan_5.jpeg',
},
{
src: '/sedan_6.jpeg',
},
{
src: '/sedan_7.jpeg',
},
{
src: '/sedan_8.jpeg',
},
{
src: '/sedan_9.jpeg',
},
{
src: '/sedan_10.jpeg',
},
{
src: '/sedan_11.jpeg',
},
{
src: '/sedan_12.jpeg',
},
{
src: '/sedan_13.jpeg',
},
{
src: '/sedan_14.jpeg',
},
],
},
// category: 'nedvizhimost',
{
id: 133423414,
title: 'Потрясающий пентхаус в самом центре Бишкека',
shortTitle: 'Потрясающий пентхаус в самом центре Бишкека',
description: '✨ Потрясающий пентхаус в самом сердце Бишкека\n'
+ '\n'
+ 'Добро пожаловать в пространство, где современный комфорт встречается с безупречным стилем. Этот великолепный пентхаус расположен на 12-м этаже нового жилого комплекса в центре Бишкека и идеально подходит для тех, кто ценит тишину, эстетику и городскую динамику одновременно.\n'
+ '\n'
+ '🌅 Прекрасные виды и продуманная планировка\n'
+ '\n'
+ 'Квартира выходит на восток и северо-запад, что наполняет пространство мягким утренним светом и атмосферой вечернего уюта. Два просторных балкона создают идеальные условия для отдыха — будь то чашка кофе на рассвете или расслабляющий вид на огни города после насыщенного дня.\n'
+ '\n'
+ '🏡 Атмосфера современного уюта\n'
+ '\n'
+ 'Пентхаус полностью оборудован и готов для жизни.\n'
+ 'Здесь продумано всё до мелочей:\n'
+ '\n'
+ 'новая современная техника\n'
+ '\n'
+ 'кофемашина Nespresso\n'
+ '\n'
+ 'супербыстрый Wi-Fi\n'
+ '\n'
+ 'система тёплого пола\n'
+ '\n'
+ 'стильная рабочая зона\n'
+ '\n'
+ 'полностью оснащённая кухня\n'
+ '\n'
+ 'Современная спальня со стеклянной стеной и встроенными жалюзи создаёт ощущение воздушности и свободы, одновременно сохраняя приватность и уют.\n'
+ '\n'
+ '🤍 Тихий оазис в центре города\n'
+ '\n'
+ 'Несмотря на расположение в эпицентре городской жизни, внутри квартиры царит абсолютный покой. Это место, где можно работать, отдыхать и наслаждаться жизнью, не выходя за пределы собственного пространства.\n'
+ '\n'
+ ' Важная информация\n'
+ '\n'
+ 'В соседнем здании ведутся строительные работы в рабочее время — именно поэтому сейчас действует специальная выгодная цена. Это отличная возможность приобрести премиальную недвижимость по привлекательной стоимости.',
type: 'rent',
category: 'nedvizhimost',
coordinates: [74.601748, 42.867657],
address: 'Бишкек, Chuy Province, Киргизия',
previewImage: {
src: '/penthause_1.avif',
},
images: [
{
src: '/penthause_2.avif',
},
{
src: '/penthause_3.avif',
},
{
src: '/penthause_4.avif',
},
{
src: '/penthause_5.avif',
},
{
src: '/penthause_6.avif',
},
{
src: '/penthause_7.avif',
},
{
src: '/penthause_8.avif',
},
{
src: '/penthause_9.avif',
},
{
src: '/penthause_10.avif',
},
{
src: '/penthause_11.avif',
},
{
src: '/penthause_12.avif',
},
{
src: '/penthause_13.avif',
},
{
src: '/penthause_14.avif',
},
],
},

View File

@@ -5,7 +5,7 @@
:toggle="false"
:ui="{
root: 'fixed bg-transparent w-full',
left: 'relative flex items-center w-full',
left: 'relative flex items-center w-full justify-between',
container: 'gap-0',
right: 'hidden',
}"
@@ -16,6 +16,16 @@
<NuxtLink to="/" class="absolute left-1/2 transform -translate-x-1/2 text-lg">
Rental
</NuxtLink>
<transition name="fade">
<UButton
v-if="showContactBar && !isMobile"
class="justify-center"
href="#contacts"
size="xl"
label="Свяжитесь с нами"
/>
</transition>
</template>
</UHeader>
@@ -23,22 +33,21 @@
<slot />
</UMain>
<UFooter class="footer">
<div class="flex flex-col md:flex-row items-center text-sm opacity-70">
<div>
© {{ new Date().getFullYear() }} Rental. Все права защищены.
</div>
</div>
</UFooter>
<BaseFooter v-if="!isMobile" />
</div>
</template>
<script setup lang="ts">
import { useMediaQuery } from '@vueuse/core'
import BaseFooter from '~/components/BaseFooter.vue'
const router = useRouter()
const route = useRoute()
const isMobile = useMediaQuery('(max-width: 1280px)')
const { cartById } = useMock()
const cart = cartById(route?.params?.id)
const showContactBar = useState('showContactBar', () => false)
function routerBack() {
const newRoute = `/${cart?.category}#variations`
@@ -47,6 +56,15 @@ function routerBack() {
</script>
<style lang="scss" scoped>
.fade-enter-active,
.fade-leave-active {
transition: 0.3s;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.footer {
@include mobile {
display: none;

View File

@@ -31,60 +31,14 @@
<slot />
</UMain>
<UFooter class="border-t border-gray-200 mt-10">
<div class="w-full max-w-7xl mx-auto py-10 px-4 grid grid-cols-1 md:grid-cols-3 gap-10 text-sm">
<div id="footer-contacts">
<h3 class="font-semibold text-base mb-3">
Контакты
</h3>
<ul class="space-y-2 opacity-80">
<li>
<span class="font-medium">Телефон:</span><br>
<a href="tel:+74951234567" class="hover:opacity-100 opacity-70">
+7 (495) 123-45-67
</a>
</li>
<li>
<span class="font-medium">Email:</span><br>
<a href="mailto:info@rental-concierge.com" class="hover:opacity-100 opacity-70">
info@rental-concierge.com
</a>
</li>
<li>
<span class="font-medium">Адрес:</span><br>
Москва, Тверская улица, 1
</li>
</ul>
</div>
<div>
<h3 class="font-semibold text-base mb-3">
Навигация
</h3>
<ul class="space-y-2 opacity-80">
<li><a href="/" class="hover:opacity-100 opacity-70">Главная</a></li>
<li><a href="/nedvizhimost" class="hover:opacity-100 opacity-70">Недвижимость</a></li>
<li><a href="/transport" class="hover:opacity-100 opacity-70">Авто</a></li>
</ul>
</div>
<div class="md:text-right opacity-70 flex flex-col justify-between">
<div class="text-lg font-bold">
Rental
</div>
<div class="mt-4 md:mt-0">
© {{ new Date().getFullYear() }} Rental.
Все права защищены.
</div>
</div>
</div>
</UFooter>
<BaseFooter />
</div>
</template>
<script setup lang="ts">
import type { TabsItem } from '@nuxt/ui'
import { useMediaQuery } from '@vueuse/core'
import BaseFooter from '~/components/BaseFooter.vue'
const isMobile = useMediaQuery('(max-width: 1280px)')

View File

@@ -36,6 +36,12 @@
</div>
</template>
<script setup lang="ts">
useHead({
title: 'Rental - консьерж-сервис',
})
</script>
<style lang="scss">
.index-page {
display: flex;

View File

@@ -88,6 +88,10 @@ const services = [
const { cartByCategory } = useMock()
const previewItems = computed(() => cartByCategory('nedvizhimost'))
useHead({
title: 'Rental - недвижимость',
})
</script>
<style lang="scss">

View File

@@ -30,7 +30,11 @@
<MapView v-if="cart?.coordinates" :marker="marker" />
<MainCarusel title="Похожие варианты" :preview-items="previewItems" />
<Contacts />
<BaseFooter />
</div>
</template>
</UDrawer>
@@ -43,13 +47,37 @@
<Gallery :preview-image="cart?.previewImage" :images="cart?.images" />
<div>
Описание:
<p class="whitespace-pre-line" v-html="cart?.description" />
<div ref="descriptionRef" class="post-page__description">
<div>
Описание:
<p class="whitespace-pre-line" v-html="cart?.description" />
</div>
<UCard
variant="subtle"
class="post-page__action"
title="Action"
>
<div>
Хотите узнать больше или оформить бронирование?<br>
Напишите нам мы с удовольствием подскажем всё, что нужно.
</div>
<template #footer>
<UButton
class="w-full flex justify-center"
href="#contacts"
size="xl"
label="Свяжитесь с нами"
/>
</template>
</UCard>
</div>
<MapView v-if="cart?.coordinates" :marker="marker" />
<MainCarusel title="Похожие варианты" :preview-items="previewItems" />
<Contacts />
</div>
</UContainer>
@@ -62,6 +90,7 @@ import { computed, shallowRef } from 'vue'
import Gallery from '~/components/Gallery.vue'
const open = ref(false)
const descriptionRef = shallowRef<HTMLElement | null>(null)
const target = shallowRef<HTMLElement | null>(null)
const targetHeight = computed(() => target.value?.offsetHeight)
const targetDrawer = shallowRef<HTMLElement | null>(null)
@@ -69,14 +98,17 @@ const targetDrawerHeight = computed(() => targetDrawer.value?.offsetHeight)
const { y } = useScroll(targetDrawer)
const isMobile = useMediaQuery('(max-width: 1024px)')
const route = useRoute()
const showContactBar = useState('showContactBar')
const { cartById } = useMock()
const { cartById, cartByCategory } = useMock()
const cart = cartById(route.params.id)
const marker = computed(() => ({
coordinates: cart?.coordinates ?? [0, 0],
subtitle: cart?.address,
}))
const previewItems = computed(() => cartByCategory(cart?.category))
const { lengthY } = useSwipe(
target,
{
@@ -106,16 +138,39 @@ definePageMeta({
})
onMounted(() => {
const el = descriptionRef.value
if (!el)
return
const observer = new IntersectionObserver(
(entries) => {
const entry = entries[0]
showContactBar.value = !entry.isIntersecting
},
{
threshold: 0.1,
},
)
observer.observe(el)
if (isMobile.value) {
document.body.style.overflow = 'hidden'
}
})
onUnmounted(() => {
showContactBar.value = false
if (isMobile.value) {
document.body.style.overflow = ''
}
})
useHead({
title: `Rental - ${cart?.title}`,
})
</script>
<style lang="scss">
@@ -159,5 +214,22 @@ onUnmounted(() => {
gap: 16px;
}
}
&__description {
flex-shrink: 1;
position: relative;
display: flex;
flex-direction: row;
gap: 20px;
justify-content: space-between;
}
&__action {
height: fit-content;
flex-shrink: 0;
position: sticky;
top: calc(64px + 26px);
width: 300px;
}
}
</style>

View File

@@ -84,6 +84,10 @@ const services = [
const { cartByCategory } = useMock()
const previewItems = computed(() => cartByCategory('transport'))
useHead({
title: 'Rental - автомобили',
})
</script>
<style lang="scss">

BIN
public/bmv_1.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
public/bmv_10.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
public/bmv_11.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

BIN
public/bmv_12.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

BIN
public/bmv_13.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
public/bmv_14.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

BIN
public/bmv_2.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
public/bmv_3.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
public/bmv_4.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
public/bmv_5.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

BIN
public/bmv_6.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
public/bmv_7.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
public/bmv_8.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
public/bmv_9.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

BIN
public/penthause_1.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
public/penthause_10.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
public/penthause_11.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
public/penthause_12.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
public/penthause_13.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
public/penthause_14.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
public/penthause_2.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
public/penthause_3.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
public/penthause_4.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
public/penthause_5.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
public/penthause_6.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
public/penthause_7.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
public/penthause_8.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
public/penthause_9.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
public/sedan_1.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
public/sedan_10.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
public/sedan_2.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
public/sedan_3.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
public/sedan_4.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
public/sedan_5.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
public/sedan_6.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

BIN
public/sedan_7.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
public/sedan_8.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

BIN
public/sedan_9.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

BIN
public/vito_1.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
public/vito_2.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
public/vito_3.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
public/vito_4.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

BIN
public/vito_5.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
public/vito_6.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
public/vito_7.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

BIN
public/vito_8.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
public/vito_9.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
public/yukon_1.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
public/yukon_2.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

BIN
public/yukon_3.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

BIN
public/yukon_4.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

BIN
public/yukon_5.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

BIN
public/yukon_6.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

BIN
public/yukon_7.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -21,7 +21,8 @@ export default defineEventHandler(async (event) => {
<b>Имя:</b> ${body.name}<br>
<b>Телефон:</b> ${body.phone}<br>
<b>Услуга:</b> ${body.service}<br>
<b>Комментарий:</b> ${body.comment}
<b>Комментарий:</b> ${body.comment}<br>
<b>Route:</b> ${body.route}
`,
})