Files
gloabl_award_front/src/views/AwardPage/components/Bloom.vue
2026-03-31 13:39:50 +08:00

273 lines
6.1 KiB
Vue

<template>
<div class="bloom flex flex-col align-center" :class="{ mobile: isMobile, pad: isPad }">
<img
v-if="isMobile"
src="@/assets/images/mobile_version_background/ellipse.png"
class="top-bg"
alt=""
/>
<div class="title" ref="titleRef">
{{ $t('AwardsPage.bloomYourCreativity') }}
</div>
<div class="season" ref="subtitleRef">
{{ $t('AwardsPage.themeOf2026') }}
</div>
<div class="desc" ref="textRef">
<p class="section-1">
<span>{{ $t('AwardsPage.bloomText.desc1.regular1') }}</span>
<span class="arial-bold">
{{ $t('AwardsPage.bloomText.desc1.bold1') }}
</span>
<span>{{ $t('AwardsPage.bloomText.desc1.regular2') }}</span>
<span class="arial-bold">
{{ $t('AwardsPage.bloomText.desc1.bold2') }}
</span>
<span>{{ $t('AwardsPage.bloomText.desc1.regular3') }}</span>
<span class="arial-bold">
{{ $t('AwardsPage.bloomText.desc1.bold3') }}
</span>
<span>{{ $t('AwardsPage.bloomText.desc1.regular4') }}</span>
<span class="arial-bold">
{{ $t('AwardsPage.bloomText.desc1.bold4') }}
</span>
<span>{{ $t('AwardsPage.bloomText.desc1.regular5') }}</span>
</p>
<!-- <p class="section-1 pad" v-show="isPad" v-html="padSection1"></p> -->
<p class="section-2">
{{ $t('AwardsPage.bloomText.desc2.regular1') }}
<span class="arial-bold">
{{ $t('AwardsPage.bloomText.desc2.bold1') }}
</span>
{{ $t('AwardsPage.bloomText.desc2.regular2') }}
</p>
</div>
<img
v-if="isMobile"
src="@/assets/images/mobile_version_background/people.png"
class="people"
alt=""
/>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, nextTick, inject } from 'vue'
import { useI18n } from 'vue-i18n'
import { gsap } from 'gsap'
const { t } = useI18n()
const isMobile = inject<boolean>('isMobile')
const isPad = inject<boolean>('isPad')
const titleRef = ref<HTMLElement | null>(null)
const subtitleRef = ref<HTMLElement | null>(null)
const textRef = ref<HTMLElement | null>(null)
// const padSection1 = computed(() => {
// return t('AwardsPage.bloomDesc1')
// })
const hasPlayedBloomAnim = ref(false)
let bloomObserver: IntersectionObserver | null = null
const setupBloomInitialState = () => {
const titleEls = [titleRef.value, subtitleRef.value].filter(Boolean) as HTMLElement[]
if (titleEls.length) {
gsap.set(titleEls, {
opacity: 0,
// start larger than final size, then animate down to scale:1
scale: 1.6,
transformOrigin: '50% 50%'
})
}
if (textRef.value) {
// start below and hidden
gsap.set(textRef.value, {
opacity: 0,
y: 60
})
}
}
const playBloomAnimation = () => {
if (hasPlayedBloomAnim.value) return
const titleEls = [titleRef.value, subtitleRef.value].filter(Boolean) as HTMLElement[]
const textEl = textRef.value
if (!titleEls.length || !textEl) return
const tl = gsap.timeline({ defaults: { ease: 'power2.out' } })
tl.to(titleEls, {
opacity: 1,
scale: 1,
duration: 0.9,
ease: 'back.out(1.6)',
stagger: 0.12
})
tl.to(
textEl,
{
opacity: 1,
y: -12,
scale: 1.05,
duration: 0.3,
ease: 'power2.out'
},
'-=0.3'
)
tl.to(
textEl,
{
y: 0,
scale: 1,
duration: 0.18,
ease: 'bounce.out'
},
'+=0.08'
)
hasPlayedBloomAnim.value = true
bloomObserver?.disconnect()
}
onMounted(() => {
nextTick(() => {
setupBloomInitialState()
if ('IntersectionObserver' in window) {
bloomObserver = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
playBloomAnimation()
}
})
},
{ threshold: 0.3 }
)
if (titleRef.value) {
bloomObserver.observe(titleRef.value)
}
} else {
// fallback
playBloomAnimation()
}
})
})
onBeforeUnmount(() => {
bloomObserver?.disconnect()
})
</script>
<style scoped lang="less">
p {
margin: 0;
padding: 0;
}
:deep(.arial-bold) {
font-family: 'ArialBold', Arial, sans-serif;
font-weight: 700;
}
.bloom {
height: 108rem;
padding-top: 12.8rem;
font-family: 'PoppinsBold';
background: url('@/assets/images/award/bloom_bg.png') no-repeat;
background-size: 100% 100%;
.title {
font-size: 4rem;
font-weight: 600;
color: #232323;
margin-bottom: 2.4rem;
}
.logo {
margin-bottom: 2.2rem;
}
.season {
font-size: 3rem;
color: #c7342c;
font-family: 'PoppinsMedium';
margin-bottom: 6.6rem;
}
.desc {
font-family: 'Arial';
font-weight: 400;
font-size: 2.4rem;
color: #585858;
text-align: center;
padding: 0 21.5rem;
line-height: 4.5rem;
margin-bottom: 12.3rem;
white-space: pre-line;
.section-1 {
font-size: 0;
span {
font-size: 2.4rem;
}
}
.section-2 {
margin-top: 4rem;
}
}
&.mobile {
background: #fff;
background-size: 100% 100%;
height: auto;
padding-top: 6rem;
position: relative;
.top-bg {
position: absolute;
top: 0;
left: 0;
// left: 50%;
// transform: translateX(-50%);
width: 100%;
height: 37.5rem;
}
.title {
font-size: 3.2rem;
margin-bottom: 0.8rem;
}
.season {
font-size: 2.4rem;
margin-bottom: 6.2rem;
}
.desc {
padding: 0 8.5vw;
font-size: 2rem;
line-height: 3rem;
white-space: normal;
margin-bottom: 7rem;
.section-1 {
font-size: 0;
span {
font-size: 2rem;
}
}
.section-2 {
font-size: 2rem;
}
}
.people {
margin: 0 6.6rem;
width: calc(100% - 13.2rem);
}
}
&.pad {
height: 84.6vw;
background: url('@/assets/images/pad_version/bloom_bg.png') no-repeat;
background-size: 100% 100%;
.arial-bold {
font-family: 'ArialBold';
font-weight: 700;
}
// .desc {
// // font-size: 2.4rem;
// }
}
}
</style>