210 lines
4.3 KiB
Vue
210 lines
4.3 KiB
Vue
// components/HeroBox.vue
|
|
<template>
|
|
<section
|
|
ref="heroBoxRef"
|
|
class="heroBox"
|
|
:class="{ 'dark': darkBackground, 'light': !darkBackground }"
|
|
:aria-label="ariaLabel"
|
|
>
|
|
<NuxtImg
|
|
provider="strapi"
|
|
:src="image"
|
|
class="hero-bg"
|
|
sizes="sm:100vw md:100vw lg:100vw"
|
|
alt=""
|
|
aria-hidden="true"
|
|
loading="eager"
|
|
priority
|
|
fetchpriority="high"
|
|
/>
|
|
<NuxtImg
|
|
v-if="overlayImage"
|
|
provider="strapi"
|
|
:src="overlayImage"
|
|
class="overlay-img"
|
|
:alt="overlayAltText"
|
|
:style="{
|
|
...overlayPosition,
|
|
width: typeof overlayWidth === 'number' ? overlayWidth + 'px' : overlayWidth,
|
|
transform: `translate3d(0, ${parallaxY}px, 0)`
|
|
}"
|
|
aria-hidden="true"
|
|
/>
|
|
<div class="container-10 heroContent">
|
|
<slot />
|
|
</div>
|
|
<svg class="sectionWave wave-bottom" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20" aria-hidden="true">
|
|
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#FFF"/>
|
|
</svg>
|
|
</section>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted, onUnmounted } from 'vue'
|
|
import { useMainStore } from '@/stores/main'
|
|
const mainStore = useMainStore()
|
|
|
|
const props = defineProps({
|
|
image: String,
|
|
ariaLabel: String,
|
|
overlayImage: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
overlayAltText: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
overlayWidth: {
|
|
type: [String, Number],
|
|
default: '200px'
|
|
},
|
|
darkBackground: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
overlayPosition: {
|
|
type: Object,
|
|
default: () => ({
|
|
bottom: '0px',
|
|
right: '0px'
|
|
})
|
|
}
|
|
})
|
|
|
|
const parallaxY = ref(0)
|
|
const heroBoxRef = ref(null)
|
|
let targetY = 0
|
|
let animationFrame
|
|
|
|
const updateParallax = () => {
|
|
parallaxY.value += (targetY - parallaxY.value) * 0.1
|
|
animationFrame = requestAnimationFrame(updateParallax)
|
|
}
|
|
|
|
const onScroll = () => {
|
|
targetY = window.scrollY * 0.3
|
|
}
|
|
|
|
const updateHeight = () => {
|
|
if (heroBoxRef.value) {
|
|
mainStore.setHeroBoxHeight(heroBoxRef.value.offsetHeight)
|
|
mainStore.setDarkHeroBack(props.darkBackground)
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
window.addEventListener('scroll', onScroll, { passive: true })
|
|
updateParallax()
|
|
updateHeight()
|
|
window.addEventListener('resize', updateHeight)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
window.removeEventListener('scroll', onScroll)
|
|
cancelAnimationFrame(animationFrame)
|
|
window.removeEventListener('resize', updateHeight)
|
|
})
|
|
</script>
|
|
|
|
|
|
<style lang="sass">
|
|
.heroBox
|
|
position: relative
|
|
min-height: 35rem
|
|
height: 70vh
|
|
display: flex
|
|
align-items: center
|
|
justify-content: center
|
|
overflow: hidden
|
|
|
|
&::after
|
|
position: absolute
|
|
content: ""
|
|
z-index: 0
|
|
top: 0
|
|
left: 0
|
|
width: 100%
|
|
height: 100%
|
|
|
|
&.dark::after
|
|
background-image: linear-gradient(
|
|
to bottom right,
|
|
rgba(255,255,255,0.4) 0%,
|
|
rgba(255,255,255,0.3) 2%,
|
|
rgba(0, 0, 0, 0.7) 60%,
|
|
rgba(255, 255, 255, 0) 100%,
|
|
transparent 100%
|
|
)
|
|
|
|
&.light::after
|
|
background-image: linear-gradient(
|
|
to bottom right,
|
|
rgba(0, 0, 0, 0.1) 0%,
|
|
rgba(255, 255, 255, 0.8) 40%,
|
|
rgba(255, 255, 255, 1) 100%
|
|
)
|
|
|
|
.hero-bg
|
|
position: absolute
|
|
inset: 0
|
|
width: 100%
|
|
height: 100%
|
|
object-fit: cover
|
|
object-position: center top
|
|
z-index: -1
|
|
|
|
.overlay-img
|
|
position: absolute
|
|
bottom: 0
|
|
right: 0
|
|
z-index: 1
|
|
height: auto
|
|
max-height: 100%
|
|
max-width: 350px
|
|
object-fit: contain
|
|
|
|
.heroContent, h1, h2, h3
|
|
position: relative
|
|
z-index: 2
|
|
|
|
h1, h2, h3
|
|
line-height: 1.5
|
|
max-width: 70%
|
|
@media (max-width: 768px)
|
|
max-width: 100%
|
|
|
|
&.dark h1, &.dark h2, &.dark h3, &.dark p
|
|
color: white
|
|
|
|
&.light h1, &.light h2, &.light h3, , &.light p
|
|
color: black
|
|
|
|
h1
|
|
margin-top: 3rem
|
|
font-size: clamp(2rem, 1.4rem + 3vw, 2.8rem)
|
|
line-height: 135%
|
|
margin-bottom: 0
|
|
font-family: 'Comfortaa'
|
|
hyphens: auto
|
|
|
|
|
|
h2
|
|
font-size: clamp(1.2rem, .7rem + 2vw, 2rem)
|
|
margin: .8rem 0 .8rem 0
|
|
font-family: 'Comfortaa'
|
|
|
|
h3
|
|
font-size: clamp(1rem, .6rem + 2vw, 1.6rem)
|
|
margin: .8rem 0 .8rem 0
|
|
p
|
|
font-size: clamp(1rem, .5rem + 2vw, 1.2rem)
|
|
margin: .8rem 0 .8rem 0
|
|
@media(max-width: $breakPointMD)
|
|
h1, h2, h3, p
|
|
line-height: 120%
|
|
|
|
.btn
|
|
margin: 1rem auto
|
|
|
|
</style> |