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

This commit is contained in:
alsaze 2025-12-02 14:11:02 +03:00
parent c889126e77
commit 311fb22f52
3 changed files with 115 additions and 8 deletions

View File

@ -43,7 +43,10 @@ import { Swiper, SwiperSlide } from 'swiper/vue'
import 'swiper/css' import 'swiper/css'
import 'swiper/css/pagination' import 'swiper/css/pagination'
const props = defineProps<{ previewImage: { src }, images: { src }[] }>() const props = defineProps<{
previewImage: { src: string }
images: { src: string }[]
}>()
const modules = [Pagination] const modules = [Pagination]
@ -57,11 +60,11 @@ const smallImages = computed(() => props?.images?.slice(1, 5))
position: relative; position: relative;
display: grid; display: grid;
grid-template-columns: 2fr 1fr; grid-template-columns: 2fr 1fr;
gap: 12px; gap: 10px;
&__main img { &__main img {
width: 100%; width: 100%;
height: 100%; height: 500px;
object-fit: cover; object-fit: cover;
border-radius: 20px; border-radius: 20px;
cursor: pointer; cursor: pointer;
@ -75,12 +78,12 @@ const smallImages = computed(() => props?.images?.slice(1, 5))
&__side { &__side {
display: grid; display: grid;
grid-template-columns: repeat(2, minmax(300px, 500px)); grid-template-columns: repeat(2, minmax(300px, 500px));
gap: 12px; gap: 10px;
} }
&__small img { &__small img {
width: 100%; width: 100%;
height: 100%; height: 245px;
object-fit: cover; object-fit: cover;
border-radius: 12px; border-radius: 12px;
cursor: pointer; cursor: pointer;

View File

@ -3,7 +3,7 @@ export const useMock = () => {
{ {
id: 13242314, id: 13242314,
title: 'Lexus LX: 2008 г., 5.7 л, Автомат, Бензиновая, Внедорожник', title: 'Lexus LX: 2008 г., 5.7 л, Автомат, Бензиновая, Внедорожник',
description: 'Основные характеристики и детали по фото: - Кузов: полноразмерный SUV, черный металлик, оригинальный фирменный обвес, хромированная решетка радиатора Lexus, рейлинги на крыше, подножки. - Оптика: биксенон/LED фары с омывателями, противотуманные фары в переднем бампере. - Колеса: легкосплавные диски темного цвета, всесезонные шины. - Салон: бежняя перфорированная кожа, второй ряд с капитанскими креслами и широким центральным подлокотником/консолью, черные защитные чехлы на передних спинках, фирменные коврики, отдельные воздуховоды и блок управления климатом для задних пассажиров. - Оснащение и удобства: мультируль, электрорегулировки сидений, подогревы, много-зонный климат-контроль, тонировка, камера/датчики (по наличию на бампере), электропривод стекол и зеркал. - Экстерьерные элементы: повторители поворота в зеркалах, хром-молдинги, спойлер, антенна-плавник. - Полный привод, высокий дорожный просвет, мощный V8 (характерно для LX 570). Автомобиль с кыргызскими номерами (KG, регион 05) по фото. Стильный черный цвет, богатая комплектация, просторный комфортный салон для дальних поездок и города. #lexus570 Скрыть', description: 'Основные характеристики и детали по фото: - Кузов: полноразмерный SUV, черный металлик, оригинальный фирменный обвес, хромированная решетка радиатора Lexus, рейлинги на крыше, подножки. - Оптика: биксенон/LED фары с омывателями, противотуманные фары в переднем бампере. - Колеса: легкосплавные диски темного цвета, всесезонные шины. - Салон: бежняя перфорированная кожа, второй ряд с капитанскими креслами и широким центральным подлокотником/консолью, черные защитные чехлы на передних спинках, фирменные коврики, отдельные воздуховоды и блок управления климатом для задних пассажиров. - Оснащение и удобства: мультируль, электрорегулировки сидений, подогревы, много-зонный климат-контроль, тонировка, камера/датчики (по наличию на бампере), электропривод стекол и зеркал. - Экстерьерные элементы: повторители поворота в зеркалах, хром-молдинги, спойлер, антенна-плавник. - Полный привод, высокий дорожный просвет, мощный V8 (характерно для LX 570). Автомобиль с кыргызскими номерами (KG, регион 05) по фото. Стильный черный цвет, богатая комплектация, просторный комфортный салон для дальних поездок и города.',
category: 'transport', category: 'transport',
previewImage: { previewImage: {
src: '/lexus_1.jpeg', src: '/lexus_1.jpeg',

View File

@ -1,7 +1,37 @@
<template> <template>
<!-- Mobile --> <!-- Mobile -->
<div v-if="isMobile" class="post-page"> <div v-if="isMobile" ref="target" class="post-page">
<Gallery :preview-image="cart?.previewImage" :images="cart?.images" /> <Gallery :preview-image="cart?.previewImage" :images="cart?.images" />
<div class="post-page__info">
{{ cart?.title }}
<UButton label="Подробности" size="xl" class="flex justify-center text-center" @click="open = !open" />
</div>
<UDrawer
v-if="isMobile"
v-model:open="open"
class="post-page__drawer"
fixed
:ui="{
content: 'fixed bg-default ring ring-default flex focus:outline-none overflow-hidden',
container: 'w-full flex flex-col gap-4 p-4 overflow-hidden',
body: 'flex-1 overflow-y-auto',
}"
>
<template #content>
<div ref="targetDrawer" class="post-page__drawer-content">
<p>{{ cart?.title }}</p>
<div>
<p>Описание:</p>
<p>{{ cart?.description }}</p>
</div>
<Contacts />
</div>
</template>
</UDrawer>
</div> </div>
<!-- Desktop --> <!-- Desktop -->
@ -20,22 +50,67 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useMediaQuery } from '@vueuse/core' import type { UseSwipeDirection } from '@vueuse/core'
import { useMediaQuery, useScroll, useSwipe } from '@vueuse/core'
import { computed, shallowRef } from 'vue'
import Gallery from '~/components/Gallery.vue' import Gallery from '~/components/Gallery.vue'
const open = ref(false)
const target = shallowRef<HTMLElement | null>(null)
const targetHeight = computed(() => target.value?.offsetHeight)
const targetDrawer = shallowRef<HTMLElement | null>(null)
const targetDrawerHeight = computed(() => targetDrawer.value?.offsetHeight)
const { y } = useScroll(targetDrawer)
const isMobile = useMediaQuery('(max-width: 1024px)') const isMobile = useMediaQuery('(max-width: 1024px)')
const route = useRoute() const route = useRoute()
const { cartById } = useMock() const { cartById } = useMock()
const cart = cartById(route.params.id) const cart = cartById(route.params.id)
const { lengthY } = useSwipe(
target,
{
passive: false,
onSwipeEnd(e: TouchEvent, direction: UseSwipeDirection) {
if (lengthY.value > 0 && targetHeight.value && (Math.abs(lengthY.value) / targetHeight.value) >= 0.1) {
open.value = true
}
},
},
)
const { lengthY: drawerLengthY } = useSwipe(
targetDrawer,
{
passive: false,
onSwipeEnd(e: TouchEvent, direction: UseSwipeDirection) {
if (drawerLengthY.value < 0 && y.value === 0 && targetDrawerHeight.value && (Math.abs(drawerLengthY.value) / targetDrawerHeight.value) >= 0.2) {
open.value = false
}
},
},
)
definePageMeta({ definePageMeta({
layout: 'cart', layout: 'cart',
}) })
onMounted(() => {
if (isMobile.value) {
document.body.style.overflow = 'hidden'
}
})
onUnmounted(() => {
if (isMobile.value) {
document.body.style.overflow = ''
}
})
</script> </script>
<style lang="scss"> <style lang="scss">
.post-page { .post-page {
position: relative;
margin-top: calc(64px + 26px); margin-top: calc(64px + 26px);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -45,5 +120,34 @@ definePageMeta({
margin-top: 0; margin-top: 0;
overflow: hidden; overflow: hidden;
} }
&__info {
background: var(--ui-bg);
border-top-right-radius: 10px;
border-top-left-radius: 10px;
position: absolute;
padding-inline: 10px;
height: 150px;
bottom: 0;
width: 100%;
z-index: 1;
display: flex;
flex-direction: column;
justify-content: center;
gap: 16px;
text-align: center;
}
&__drawer {
&-content {
overflow-y: auto;
padding: 20px;
display: flex;
flex-direction: column;
gap: 16px;
}
}
} }
</style> </style>