Files
Website/resources/js/components/SMHero.vue

199 lines
4.5 KiB
Vue

<template>
<section class="hero">
<SMLoading v-if="!loaded" large />
<template v-else>
<div class="hero-background" :style="heroStyles"></div>
<SMContainer class="hero-container">
<div class="hero-content">
<h1>{{ props.title }}</h1>
<p>{{ props.excerpt }}</p>
<div class="hero-buttons">
<SMButton
v-if="loaded"
type="primary"
:to="props.to"
:label="props.more" />
</div>
</div>
</SMContainer>
<div class="hero-caption">
<router-link v-if="loaded" :to="props.to">{{
props.imageTitle
}}</router-link>
</div>
</template>
</section>
</template>
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
import { api, getApiResultData } from "../helpers/api";
import { ArticleCollection } from "../helpers/api.types";
import { mediaGetVariantUrl } from "../helpers/media";
import { excerpt } from "../helpers/string";
import SMButton from "./SMButton.vue";
import SMLoading from "./SMLoading.vue";
const props = defineProps({
title: {
type: String,
required: true,
},
excerpt: {
type: String,
required: true,
},
imageUrl: {
type: String,
required: true,
},
imageTitle: {
type: String,
required: true,
},
to: {
type: Object,
required: true,
},
more: {
type: String,
default: "Read More",
required: false,
},
});
const loaded = ref(false);
const translateY = ref(0);
const heroStyles = ref({
backgroundImage: "none",
transform: "translateY(0px)",
});
const handleScroll = () => {
const scrollTop = window.scrollY;
translateY.value = scrollTop / 2.5;
};
watch(translateY, () => {
heroStyles.value.transform = `translateY(${translateY.value}px)`;
});
const updateImageUrl = (url: string) => {
heroStyles.value.backgroundImage = `linear-gradient(to right, rgba(0, 0, 0, 0.7),rgba(0, 0, 0, 0.2)),url('${url}')`;
loaded.value = true;
};
watch(
() => props.imageUrl,
() => {
updateImageUrl(props.imageUrl);
}
);
onMounted(() => {
window.addEventListener("scroll", handleScroll);
});
onBeforeUnmount(() => {
window.removeEventListener("scroll", handleScroll);
});
if (props.imageUrl && props.imageUrl !== "") {
updateImageUrl(props.imageUrl);
}
</script>
<style lang="scss">
.hero {
display: flex;
position: relative;
overflow: hidden;
min-height: 101vh;
.hero-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.hero-container {
align-items: flex-start;
}
.hero-content {
position: relative;
margin: 150px 32px 120px;
max-width: 640px;
h1 {
font-size: 300%;
margin-bottom: 20px;
max-width: 550px;
color: var(--hero-color-text);
text-align: left;
text-shadow: var(--hero-shadow);
}
p {
max-width: 550px;
color: var(--hero-color-text);
text-align: left;
text-shadow: var(--hero-shadow);
}
}
.hero-caption {
position: absolute;
bottom: 14px;
right: 30px;
color: var(--hero-caption-color-text);
font-size: 80%;
padding: 6px 12px;
background-color: var(--hero-caption-color);
a {
color: inherit;
transition: color 0.1s ease-in-out;
text-decoration: none;
&:hover {
text-decoration: none;
color: var(--hero-caption-color-link);
}
}
}
.hero-buttons {
padding-top: 48px;
.primary {
background-color: var(--primary-color-dark);
}
}
}
@media only screen and (max-width: 640px) {
.hero {
.hero-container {
align-items: center;
}
.hero-content {
margin: 150px 0;
}
.hero-buttons {
.button {
display: block;
text-align: center;
}
}
}
}
</style>