This commit is contained in:
parent
5f3c4057e7
commit
5f250b8b6c
8
app.vue
8
app.vue
@ -6,6 +6,14 @@
|
|||||||
</UApp>
|
</UApp>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import gsap from 'gsap'
|
||||||
|
import { ScrollToPlugin } from 'gsap/ScrollToPlugin'
|
||||||
|
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollTrigger, ScrollToPlugin)
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@use '@/assets/scss/main' as *;
|
@use '@/assets/scss/main' as *;
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
:ui="{ container: '!p-0' }"
|
:ui="{ container: '!p-0' }"
|
||||||
>
|
>
|
||||||
<template #body>
|
<template #body>
|
||||||
<div class="benefits">
|
<div ref="benefitsRef" class="benefits">
|
||||||
<div
|
<div
|
||||||
v-for="benefit in benefits"
|
v-for="benefit in benefits"
|
||||||
:key="benefit.title"
|
:key="benefit.title"
|
||||||
@ -30,6 +30,41 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import gsap from 'gsap'
|
||||||
|
import ScrollTrigger from 'gsap/ScrollTrigger'
|
||||||
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollTrigger)
|
||||||
|
|
||||||
|
const benefitsRef = ref()
|
||||||
|
let benefitsCtx
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
desktopAnimation()
|
||||||
|
})
|
||||||
|
|
||||||
|
function desktopAnimation() {
|
||||||
|
benefitsCtx = gsap.context((self) => {
|
||||||
|
const boxes = self.selector('.benefit')
|
||||||
|
|
||||||
|
const tl = gsap.timeline({
|
||||||
|
scrollTrigger: {
|
||||||
|
trigger: benefitsRef.value,
|
||||||
|
start: 'top 80%',
|
||||||
|
toggleActions: 'play none none reverse',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
tl.from(boxes, {
|
||||||
|
y: 50,
|
||||||
|
opacity: 0,
|
||||||
|
duration: 0.8,
|
||||||
|
ease: 'power3.out',
|
||||||
|
stagger: 0.25,
|
||||||
|
})
|
||||||
|
}, benefitsRef.value)
|
||||||
|
}
|
||||||
|
|
||||||
const benefits = [
|
const benefits = [
|
||||||
{
|
{
|
||||||
icon: '⏱️',
|
icon: '⏱️',
|
||||||
@ -62,6 +97,10 @@ const benefits = [
|
|||||||
description: 'Более 10 лет на рынке консьерж-услуг',
|
description: 'Более 10 лет на рынке консьерж-услуг',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
benefitsCtx?.revert()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@ -6,25 +6,22 @@
|
|||||||
:ui="{ container: '!p-0' }"
|
:ui="{ container: '!p-0' }"
|
||||||
>
|
>
|
||||||
<template #body>
|
<template #body>
|
||||||
<div class="how-works">
|
<div ref="howWorksRef" class="how-works">
|
||||||
<UCard
|
<UCard
|
||||||
v-for="item in items"
|
v-for="item in items"
|
||||||
:key="item.title"
|
:key="item.title"
|
||||||
class="how-work"
|
class="how-work"
|
||||||
:ui="{ body: 'flex flex-col gap-4 h-[350px] !pb-15' }"
|
:ui="cardUi"
|
||||||
>
|
>
|
||||||
<div class="how-work__number">
|
<div class="how-work__number">
|
||||||
{{ item.number }}
|
{{ item.number }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="how-work__icon">
|
<div class="how-work__icon">
|
||||||
{{ item.icon }}
|
{{ item.icon }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="how-work__title">
|
<div class="how-work__title">
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="how-work__description">
|
<div class="how-work__description">
|
||||||
{{ item.description }}
|
{{ item.description }}
|
||||||
</div>
|
</div>
|
||||||
@ -35,6 +32,50 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useMediaQuery } from '@vueuse/core'
|
||||||
|
import gsap from 'gsap'
|
||||||
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
|
||||||
|
const isMobile = useMediaQuery('(max-width: 1280px)')
|
||||||
|
const cardUi = computed(() => {
|
||||||
|
return isMobile.value
|
||||||
|
? { body: 'flex flex-col gap-2 h-[270px] !pb-5' }
|
||||||
|
: { body: 'flex flex-col gap-4 h-[350px] !pb-15' }
|
||||||
|
})
|
||||||
|
|
||||||
|
const howWorksRef = ref()
|
||||||
|
let ctx
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
desktopAnimation()
|
||||||
|
})
|
||||||
|
|
||||||
|
function desktopAnimation() {
|
||||||
|
ctx = gsap.context((self) => {
|
||||||
|
const boxes = self.selector('.how-work')
|
||||||
|
|
||||||
|
const tl = gsap.timeline({
|
||||||
|
scrollTrigger: {
|
||||||
|
trigger: howWorksRef.value,
|
||||||
|
start: 'top 50%',
|
||||||
|
toggleActions: 'play none none reverse',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
tl.from(boxes, {
|
||||||
|
x: -80,
|
||||||
|
opacity: 0,
|
||||||
|
duration: 0.8,
|
||||||
|
ease: 'power3.out',
|
||||||
|
stagger: 0.25,
|
||||||
|
})
|
||||||
|
}, howWorksRef.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
ctx.revert()
|
||||||
|
})
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
icon: '💬',
|
icon: '💬',
|
||||||
@ -72,7 +113,7 @@ const items = [
|
|||||||
|
|
||||||
@include mobile {
|
@include mobile {
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
grid-template-columns: repeat(2, minmax(150px, 350px));
|
grid-template-columns: repeat(1, minmax(150px, 350px));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<UPageSection
|
<UPageSection
|
||||||
|
id="services"
|
||||||
title="Что мы предлагаем"
|
title="Что мы предлагаем"
|
||||||
description="Полный спектр консьерж-услуг для работы с недвижимостью и автомобилями"
|
description="Полный спектр консьерж-услуг для работы с недвижимостью и автомобилями"
|
||||||
:ui="{ container: '!p-0' }"
|
:ui="{ container: '!p-0' }"
|
||||||
>
|
>
|
||||||
<template #body>
|
<template #body>
|
||||||
<div class="services">
|
<div ref="servicesRef" class="services">
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
v-for="service in services"
|
v-for="service in services"
|
||||||
:key="service.name"
|
:key="service.name"
|
||||||
@ -41,6 +42,52 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import gsap from 'gsap'
|
||||||
|
import ScrollTrigger from 'gsap/ScrollTrigger'
|
||||||
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollTrigger)
|
||||||
|
|
||||||
|
const servicesRef = ref()
|
||||||
|
let servicesCtx
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
servicesAnimation()
|
||||||
|
})
|
||||||
|
|
||||||
|
function servicesAnimation() {
|
||||||
|
servicesCtx = gsap.context((self) => {
|
||||||
|
const cards = self.selector('.service')
|
||||||
|
|
||||||
|
cards.forEach((card) => {
|
||||||
|
gsap.from(card, {
|
||||||
|
y: 80,
|
||||||
|
rotateY: 15,
|
||||||
|
opacity: 0,
|
||||||
|
duration: 1,
|
||||||
|
ease: 'power4.out',
|
||||||
|
scrollTrigger: {
|
||||||
|
trigger: card,
|
||||||
|
start: 'top 70%',
|
||||||
|
toggleActions: 'play none none reverse',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
cards.forEach((card) => {
|
||||||
|
const hover = gsap.to(card, {
|
||||||
|
scale: 1.01,
|
||||||
|
duration: 0.3,
|
||||||
|
paused: true,
|
||||||
|
ease: 'power2.out',
|
||||||
|
})
|
||||||
|
|
||||||
|
card.addEventListener('mouseenter', () => hover.play())
|
||||||
|
card.addEventListener('mouseleave', () => hover.reverse())
|
||||||
|
})
|
||||||
|
}, servicesRef.value)
|
||||||
|
}
|
||||||
|
|
||||||
const services = [
|
const services = [
|
||||||
{
|
{
|
||||||
name: 'nedvizhimost',
|
name: 'nedvizhimost',
|
||||||
@ -87,6 +134,10 @@ const services = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
servicesCtx?.revert()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -109,11 +160,6 @@ const services = [
|
|||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6);
|
||||||
transition: 0.15s ease-out;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
transform: scale(1.01);
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@ -21,6 +21,9 @@ export default defineNuxtConfig({
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
css: ['~/assets/css/main.css', '~/assets/scss/main.scss'],
|
css: ['~/assets/css/main.css', '~/assets/scss/main.scss'],
|
||||||
|
build: {
|
||||||
|
transpile: ['gsap'],
|
||||||
|
},
|
||||||
i18n: {
|
i18n: {
|
||||||
locales: [
|
locales: [
|
||||||
{ code: 'en', name: 'English', file: 'en.json' },
|
{ code: 'en', name: 'English', file: 'en.json' },
|
||||||
|
|||||||
@ -3,9 +3,26 @@
|
|||||||
<UPageHero
|
<UPageHero
|
||||||
title="Консьерж-сервис премиум класса"
|
title="Консьерж-сервис премиум класса"
|
||||||
:description="`Недвижимость и авто под ключ\nМы берем на себя все заботы по поиску, проверке и оформлению недвижимости и автомобилей. Экономьте время — доверьтесь профессионалам.`"
|
:description="`Недвижимость и авто под ключ\nМы берем на себя все заботы по поиску, проверке и оформлению недвижимости и автомобилей. Экономьте время — доверьтесь профессионалам.`"
|
||||||
:links="links"
|
|
||||||
class="index-page__hero"
|
class="index-page__hero"
|
||||||
/>
|
>
|
||||||
|
<template #footer>
|
||||||
|
<div class="flex gap-2 place-content-center">
|
||||||
|
<UButton
|
||||||
|
size="xl"
|
||||||
|
label="Узанть больше"
|
||||||
|
href="#services"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<UButton
|
||||||
|
size="xl"
|
||||||
|
label="Почему выбирают нас"
|
||||||
|
href="#benefits"
|
||||||
|
color="neutral"
|
||||||
|
variant="subtle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UPageHero>
|
||||||
|
|
||||||
<UContainer class="flex flex-col gap-32 my-32">
|
<UContainer class="flex flex-col gap-32 my-32">
|
||||||
<Services />
|
<Services />
|
||||||
@ -19,21 +36,6 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Services from '~/components/Services.vue'
|
import Services from '~/components/Services.vue'
|
||||||
|
|
||||||
const links = computed(() => [
|
|
||||||
{
|
|
||||||
label: 'Начать работу',
|
|
||||||
to: '/docs/getting-started',
|
|
||||||
icon: 'i-lucide-square-play',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Узнать больше',
|
|
||||||
to: '/docs/getting-started/theme/design-system',
|
|
||||||
color: 'neutral',
|
|
||||||
variant: 'subtle',
|
|
||||||
trailingIcon: 'i-lucide-arrow-right',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user