feat: 首页轮播图动画
This commit is contained in:
23
pnpm-lock.yaml
generated
23
pnpm-lock.yaml
generated
@@ -14,9 +14,18 @@ importers:
|
|||||||
'@unhead/vue':
|
'@unhead/vue':
|
||||||
specifier: ^2.1.15
|
specifier: ^2.1.15
|
||||||
version: 2.1.15(vue@3.5.34(typescript@6.0.3))
|
version: 2.1.15(vue@3.5.34(typescript@6.0.3))
|
||||||
|
gsap:
|
||||||
|
specifier: ^3.15.0
|
||||||
|
version: 3.15.0
|
||||||
|
less:
|
||||||
|
specifier: ^4.6.4
|
||||||
|
version: 4.6.4
|
||||||
|
unhead:
|
||||||
|
specifier: 2.1.15
|
||||||
|
version: 2.1.15
|
||||||
vite-ssg:
|
vite-ssg:
|
||||||
specifier: ^28.3.0
|
specifier: ^28.3.0
|
||||||
version: 28.3.0(unhead@3.1.0(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1)))(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1))(vue-router@4.6.4(vue@3.5.34(typescript@6.0.3)))(vue@3.5.34(typescript@6.0.3))
|
version: 28.3.0(unhead@2.1.15)(vite@8.0.12(@types/node@24.12.4)(less@4.6.4)(terser@5.47.1))(vue-router@4.6.4(vue@3.5.34(typescript@6.0.3)))(vue@3.5.34(typescript@6.0.3))
|
||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.34
|
specifier: ^3.5.34
|
||||||
version: 3.5.34(typescript@6.0.3)
|
version: 3.5.34(typescript@6.0.3)
|
||||||
@@ -203,42 +212,36 @@ packages:
|
|||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-arm64-musl@1.0.0':
|
'@rolldown/binding-linux-arm64-musl@1.0.0':
|
||||||
resolution: {integrity: sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==}
|
resolution: {integrity: sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-ppc64-gnu@1.0.0':
|
'@rolldown/binding-linux-ppc64-gnu@1.0.0':
|
||||||
resolution: {integrity: sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==}
|
resolution: {integrity: sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-s390x-gnu@1.0.0':
|
'@rolldown/binding-linux-s390x-gnu@1.0.0':
|
||||||
resolution: {integrity: sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==}
|
resolution: {integrity: sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-x64-gnu@1.0.0':
|
'@rolldown/binding-linux-x64-gnu@1.0.0':
|
||||||
resolution: {integrity: sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==}
|
resolution: {integrity: sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-x64-musl@1.0.0':
|
'@rolldown/binding-linux-x64-musl@1.0.0':
|
||||||
resolution: {integrity: sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==}
|
resolution: {integrity: sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rolldown/binding-openharmony-arm64@1.0.0':
|
'@rolldown/binding-openharmony-arm64@1.0.0':
|
||||||
resolution: {integrity: sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==}
|
resolution: {integrity: sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==}
|
||||||
@@ -562,28 +565,24 @@ packages:
|
|||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
lightningcss-linux-arm64-musl@1.32.0:
|
lightningcss-linux-arm64-musl@1.32.0:
|
||||||
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
|
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
lightningcss-linux-x64-gnu@1.32.0:
|
lightningcss-linux-x64-gnu@1.32.0:
|
||||||
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
|
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
lightningcss-linux-x64-musl@1.32.0:
|
lightningcss-linux-x64-musl@1.32.0:
|
||||||
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
|
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
lightningcss-win32-arm64-msvc@1.32.0:
|
lightningcss-win32-arm64-msvc@1.32.0:
|
||||||
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
|
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
|
||||||
@@ -1556,7 +1555,7 @@ snapshots:
|
|||||||
|
|
||||||
vite-ssg-sitemap@0.10.0: {}
|
vite-ssg-sitemap@0.10.0: {}
|
||||||
|
|
||||||
vite-ssg@28.3.0(unhead@3.1.0(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1)))(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1))(vue-router@4.6.4(vue@3.5.34(typescript@6.0.3)))(vue@3.5.34(typescript@6.0.3)):
|
vite-ssg@28.3.0(unhead@2.1.15)(vite@8.0.12(@types/node@24.12.4)(less@4.6.4)(terser@5.47.1))(vue-router@4.6.4(vue@3.5.34(typescript@6.0.3)))(vue@3.5.34(typescript@6.0.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@unhead/dom': 2.1.15(unhead@2.1.15)
|
'@unhead/dom': 2.1.15(unhead@2.1.15)
|
||||||
'@unhead/vue': 2.1.15(vue@3.5.34(typescript@6.0.3))
|
'@unhead/vue': 2.1.15(vue@3.5.34(typescript@6.0.3))
|
||||||
|
|||||||
@@ -1,13 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="carousel-container" aria-label="Featured content">
|
<section
|
||||||
|
class="carousel-container"
|
||||||
|
aria-label="Featured content"
|
||||||
|
@mouseenter="pauseAutoplay"
|
||||||
|
@mouseleave="resumeAutoplay"
|
||||||
|
>
|
||||||
<KagolCarousel
|
<KagolCarousel
|
||||||
v-model="activePage"
|
v-model="activePage"
|
||||||
class="home-carousel"
|
class="home-carousel"
|
||||||
:autoplay="isAutoplayEnabled"
|
:autoplay="false"
|
||||||
:interval="5000"
|
:interval="1000"
|
||||||
>
|
>
|
||||||
<article v-for="slide in slides" :key="slide.id" class="carousel-slide">
|
<article
|
||||||
<img class="carousel-image" :src="slide.image" :alt="slide.alt" />
|
v-for="slide in slides"
|
||||||
|
:key="slide.id"
|
||||||
|
ref="slideEls"
|
||||||
|
class="carousel-slide"
|
||||||
|
>
|
||||||
|
<div class="mask"></div>
|
||||||
|
<div class="banner-title" v-if="slide.title">{{ slide.title }}</div>
|
||||||
|
<img
|
||||||
|
v-if="!slide.video"
|
||||||
|
class="carousel-banner image"
|
||||||
|
:src="slide.image"
|
||||||
|
:alt="slide.alt"
|
||||||
|
/>
|
||||||
|
<video
|
||||||
|
v-else
|
||||||
|
class="carousel-banner video"
|
||||||
|
:alt="slide.alt"
|
||||||
|
:controls="false"
|
||||||
|
autoplay
|
||||||
|
muted
|
||||||
|
loop
|
||||||
|
>
|
||||||
|
<source :src="slide.video" type="video/mp4" />
|
||||||
|
</video>
|
||||||
|
|
||||||
|
<div class="desc flex flex-center" v-if="slide.description">
|
||||||
|
<span class="desc-fill" aria-hidden="true"></span>
|
||||||
|
<span class="desc-index-group">
|
||||||
|
<span class="desc-line" aria-hidden="true"></span>
|
||||||
|
<span class="desc-index-frame">
|
||||||
|
<span class="desc-index">{{ slide.number }}</span>
|
||||||
|
<span class="desc-index-cover" aria-hidden="true"></span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<p class="desc-copy">{{ slide.description }}</p>
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<template #pagination="{ prevPage, nextPage }">
|
<template #pagination="{ prevPage, nextPage }">
|
||||||
@@ -43,58 +83,290 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Carousel as KagolCarousel } from '@kagol/vue-carousel'
|
import { Carousel as KagolCarousel } from '@kagol/vue-carousel'
|
||||||
import '@kagol/vue-carousel/dist/style.css'
|
import '@kagol/vue-carousel/dist/style.css'
|
||||||
import { onMounted, shallowRef } from 'vue'
|
import { gsap } from 'gsap'
|
||||||
|
import {
|
||||||
|
nextTick,
|
||||||
|
onBeforeUnmount,
|
||||||
|
onMounted,
|
||||||
|
shallowRef,
|
||||||
|
useTemplateRef,
|
||||||
|
watch
|
||||||
|
} from 'vue'
|
||||||
import mainBanner01 from '../../../assets/images/home/mainbanner01.jpg'
|
import mainBanner01 from '../../../assets/images/home/mainbanner01.jpg'
|
||||||
import mainBanner02 from '../../../assets/images/home/mainbanner02.jpg'
|
import mainBanner02 from '../../../assets/images/home/mainbanner02.jpg'
|
||||||
|
import Video from '@/assets/images/home/hero-desktop.mp4'
|
||||||
|
|
||||||
|
type HomeSlide = {
|
||||||
|
id: string
|
||||||
|
image: string
|
||||||
|
video: string
|
||||||
|
alt: string
|
||||||
|
title?: string
|
||||||
|
number?: string
|
||||||
|
description?: string
|
||||||
|
}
|
||||||
|
|
||||||
const activePage = shallowRef(1)
|
const activePage = shallowRef(1)
|
||||||
const isAutoplayEnabled = shallowRef(false)
|
const isAutoplayEnabled = shallowRef(false)
|
||||||
const slides = [
|
const slideEls = useTemplateRef<HTMLElement[]>('slideEls')
|
||||||
|
const slides: readonly HomeSlide[] = [
|
||||||
{
|
{
|
||||||
id: 'aida',
|
id: 'aida',
|
||||||
image: mainBanner01,
|
image: mainBanner01,
|
||||||
alt: 'AiDA product banner'
|
video: '',
|
||||||
|
alt: 'Code Create product banner',
|
||||||
|
title: 'Shaping the future\nof fashion design',
|
||||||
|
number: '01',
|
||||||
|
description:
|
||||||
|
"World's first and only designer-led AI system that streamlines ideation from hours to seconds"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'mixi',
|
id: 'mixi',
|
||||||
image: mainBanner02,
|
image: mainBanner02,
|
||||||
alt: 'Mixi product banner'
|
video: '',
|
||||||
|
alt: 'Code Create product banner',
|
||||||
|
title: 'Be the game changer,\n subscribe now!',
|
||||||
|
number: '02',
|
||||||
|
description: 'Make the first move to streamline and facilitate your inspiration process'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'video',
|
||||||
|
image: '',
|
||||||
|
video: Video,
|
||||||
|
alt: 'Code Create product video banner'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const descAnimationDelay = 1
|
||||||
|
let activeSlideIndex: number | null = null
|
||||||
|
let descAnimationFrame = 0
|
||||||
|
let descTimeline: ReturnType<typeof gsap.timeline> | null = null
|
||||||
|
|
||||||
|
function getActiveSlideIndex() {
|
||||||
|
const slideCount = slides.length
|
||||||
|
|
||||||
|
return ((activePage.value - 1) % slideCount + slideCount) % slideCount
|
||||||
|
}
|
||||||
|
|
||||||
|
function prefersReducedMotion() {
|
||||||
|
return window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
function playDescAnimation(slideIndex: number) {
|
||||||
|
const activeSlide = slideEls.value?.[slideIndex]
|
||||||
|
const desc = activeSlide?.querySelector<HTMLElement>('.desc')
|
||||||
|
const fill = desc?.querySelector<HTMLElement>('.desc-fill')
|
||||||
|
const line = desc?.querySelector<HTMLElement>('.desc-line')
|
||||||
|
const index = desc?.querySelector<HTMLElement>('.desc-index')
|
||||||
|
const cover = desc?.querySelector<HTMLElement>('.desc-index-cover')
|
||||||
|
const copy = desc?.querySelector<HTMLElement>('.desc-copy')
|
||||||
|
|
||||||
|
descTimeline?.kill()
|
||||||
|
descTimeline = null
|
||||||
|
|
||||||
|
if (!fill || !line || !index || !cover || !copy) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
gsap.killTweensOf([fill, line, index, cover, copy])
|
||||||
|
|
||||||
|
if (prefersReducedMotion()) {
|
||||||
|
gsap.set(fill, { width: '100%' })
|
||||||
|
gsap.set(line, { autoAlpha: 1, width: 1, x: 0 })
|
||||||
|
gsap.set(index, { autoAlpha: 1, x: 0 })
|
||||||
|
gsap.set(cover, { autoAlpha: 0, xPercent: 110 })
|
||||||
|
gsap.set(copy, { autoAlpha: 1, x: 0 })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
gsap.set(fill, { width: 0 })
|
||||||
|
gsap.set(line, { autoAlpha: 0, width: 5, x: 18 })
|
||||||
|
gsap.set(index, { autoAlpha: 0, x: -34 })
|
||||||
|
gsap.set(cover, { autoAlpha: 0, xPercent: 0 })
|
||||||
|
gsap.set(copy, { autoAlpha: 0, x: 22 })
|
||||||
|
|
||||||
|
descTimeline = gsap
|
||||||
|
.timeline({
|
||||||
|
delay: descAnimationDelay,
|
||||||
|
defaults: {
|
||||||
|
ease: 'power3.out'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.addLabel('panel', 0)
|
||||||
|
.to(fill, { duration: 1.05, ease: 'power2.out', width: '100%' }, 'panel')
|
||||||
|
.to(line, { autoAlpha: 1, duration: 0.9, width: 1, x: 0 }, 'panel+=0.12')
|
||||||
|
.addLabel('number', 1.18)
|
||||||
|
.set(index, { autoAlpha: 1 }, 'number')
|
||||||
|
.set(cover, { autoAlpha: 1 }, 'number')
|
||||||
|
.to(index, { duration: 0.7, x: 0 }, 'number')
|
||||||
|
.to(cover, { duration: 0.72, ease: 'power2.inOut', xPercent: 110 }, 'number+=0.08')
|
||||||
|
.to(copy, { autoAlpha: 1, duration: 0.72, x: 0 }, '>')
|
||||||
|
}
|
||||||
|
|
||||||
|
function queueDescAnimation() {
|
||||||
|
const slideIndex = getActiveSlideIndex()
|
||||||
|
|
||||||
|
if (slideIndex === activeSlideIndex) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
activeSlideIndex = slideIndex
|
||||||
|
nextTick(() => {
|
||||||
|
if (descAnimationFrame) {
|
||||||
|
window.cancelAnimationFrame(descAnimationFrame)
|
||||||
|
}
|
||||||
|
|
||||||
|
descAnimationFrame = window.requestAnimationFrame(() => {
|
||||||
|
descAnimationFrame = 0
|
||||||
|
playDescAnimation(slideIndex)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function pauseAutoplay() {
|
||||||
|
isAutoplayEnabled.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function resumeAutoplay() {
|
||||||
|
isAutoplayEnabled.value = true
|
||||||
}
|
}
|
||||||
] as const
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
isAutoplayEnabled.value = true
|
resumeAutoplay()
|
||||||
|
queueDescAnimation()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (descAnimationFrame) {
|
||||||
|
window.cancelAnimationFrame(descAnimationFrame)
|
||||||
|
}
|
||||||
|
|
||||||
|
descTimeline?.kill()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(activePage, queueDescAnimation)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped lang="less">
|
||||||
.carousel-container {
|
.carousel-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #070b14;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-carousel {
|
.home-carousel {
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.carousel-slide {
|
.carousel-slide {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
aspect-ratio: 16 / 9;
|
aspect-ratio: 16 / 9;
|
||||||
min-height: 360px;
|
height: 960px;
|
||||||
max-height: 680px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #070b14;
|
.mask {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.35);
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
.carousel-banner {
|
||||||
.carousel-image {
|
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.banner-title {
|
||||||
|
position: absolute;
|
||||||
|
right: 50%;
|
||||||
|
top: 50%;
|
||||||
|
white-space: pre-line;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 64px;
|
||||||
|
font-family: 'Poppins';
|
||||||
|
transform: translateY(-70%);
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 3;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
height: 140px;
|
||||||
|
width: 656px;
|
||||||
|
color: #ffffff;
|
||||||
|
background: transparent;
|
||||||
|
isolation: isolate;
|
||||||
|
}
|
||||||
|
.desc-fill {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0 auto 0 0;
|
||||||
|
z-index: 0;
|
||||||
|
display: block;
|
||||||
|
width: 0;
|
||||||
|
background: #a51f24;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.desc-index-group {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
.desc-line {
|
||||||
|
position: absolute;
|
||||||
|
top: -160%;
|
||||||
|
left: 50%;
|
||||||
|
display: block;
|
||||||
|
width: 1px;
|
||||||
|
height: 65px;
|
||||||
|
background: rgba(255, 255, 255, 0.72);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
will-change: transform, width, opacity;
|
||||||
|
}
|
||||||
|
.desc-index-frame {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.desc-index {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: block;
|
||||||
|
font-family: 'Poppins';
|
||||||
|
font-size: 52px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
opacity: 0;
|
||||||
|
will-change: transform, opacity;
|
||||||
|
}
|
||||||
|
.desc-index-cover {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 2;
|
||||||
|
display: block;
|
||||||
|
background: #ffffff;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
.desc-copy {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
max-width: 440px;
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'Poppins';
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.45;
|
||||||
|
opacity: 0;
|
||||||
|
will-change: transform, opacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
.carousel-pagination {
|
.carousel-pagination {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
@@ -108,11 +380,6 @@
|
|||||||
transition: transform 0.28s ease;
|
transition: transform 0.28s ease;
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carousel-container:hover .carousel-pagination {
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.carousel-pagination-button {
|
.carousel-pagination-button {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -159,6 +426,11 @@
|
|||||||
.carousel-pagination-arrow-next {
|
.carousel-pagination-arrow-next {
|
||||||
transform: translate(-50%, -50%) rotate(45deg);
|
transform: translate(-50%, -50%) rotate(45deg);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-container:hover .carousel-pagination {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.xui-carousel) {
|
:deep(.xui-carousel) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -173,6 +445,29 @@
|
|||||||
min-height: 320px;
|
min-height: 320px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.home-carousel {
|
||||||
|
.carousel-slide {
|
||||||
|
.desc {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
height: auto;
|
||||||
|
min-height: 92px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
.desc-line {
|
||||||
|
top: -28px;
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
.desc-index {
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
.desc-copy {
|
||||||
|
max-width: none;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.carousel-pagination-arrow {
|
.carousel-pagination-arrow {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
|||||||
@@ -1,11 +1,34 @@
|
|||||||
html,body{
|
html,
|
||||||
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-col {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-center {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-1 {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user