Files
th-website/src/components/big/TextSection.vue
2026-08-12 21:34:07 +02:00

251 lines
5.1 KiB
Vue

<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import gsap from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger";
import Flip from "gsap/dist/Flip";
import { checkCompatEnabled } from "@vue/compiler-core";
gsap.registerPlugin(Flip, ScrollTrigger);
let flipCtx;
const createTimeline = () => {
flipCtx && flipCtx.revert(); // alte Flip-Timeline zurücksetzen
flipCtx = gsap.context(() => {
const flipConfig = { ease: "none", duration: 1 };
// Flip-States der Marker holen
const secondState = Flip.getState(".second .marker");
const thirdState = Flip.getState(".third .marker");
// Timeline mit ScrollTrigger
const tl = gsap.timeline({
scrollTrigger: {
trigger: ".container.initial",
start: "clamp(top center)",
endTrigger: ".final",
end: "clamp(bottom center)",
scrub: 1,
},
});
// initial -> second
tl.add(Flip.fit(".circle", secondState, flipConfig)).add(() => {
gsap.set(".second-btn", {
opacity: 1,
pointerEvents: "auto",
zIndex: 1000,
});
}, "+=0.1");
// second -> third
tl.add(Flip.fit(".circle", thirdState, flipConfig)).add(() => {
gsap.set(".third-btn", { opacity: 1, pointerEvents: "auto" });
}, "+=0.01");
});
};
onMounted(() => {
createTimeline();
window.addEventListener("resize", createTimeline);
ScrollTrigger.refresh();
});
onUnmounted(() => {
flipCtx?.revert();
window.removeEventListener("resize", createTimeline);
});
window.addEventListener("resize", createTimeline);
</script>
<template>
<section class="text-section">
<div class="main">
<div class="container initial">
<div class="circle"></div>
</div>
<div class="container second">
<div class="experience-text">
<h2>About Me</h2>
</div>
<div class="marker"></div>
<router-link to="/motion/me">
<button class="btn second-btn">Get to know me</button>
</router-link>
</div>
<div class="container third">
<div class="experience-text">
<h2>Enten?</h2>
</div>
<div class="marker"></div>
<router-link to="/ducks">
<button class="btn third-btn">zu den Enten</button>
</router-link>
</div>
<div class="container fourth">
<div class="experience-text">
<h2>Here is the final step!</h2>
</div>
<div class="marker"></div>
<button class="btn fourth-btn">Next</button>
</div>
</div>
<div class="spacer final"></div>
</section>
</template>
<style scoped>
h2 {
font-size: 1.2rem;
margin-bottom: 2rem;
}
.highlight {
background: linear-gradient(90deg, #ffffff, #ffffff);
background-repeat: no-repeat;
background-size: 0% 100%;
background-position: left;
padding: 0 0.3rem;
}
.btn {
background-color: white;
color: #1a1a2e; /* dunkler Text */
border: none;
padding: 0.6rem 1.5rem;
font-size: 1rem;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
opacity: 0;
}
.btn:hover {
background-color: #f0f0f0;
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}
.btn:active {
transform: translateY(0);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}
body {
background-image:
linear-gradient(rgba(255, 255, 255, 0.05) 2px, transparent 2px),
linear-gradient(90deg, rgba(255, 255, 255, 0.05) 2px, transparent 2px),
linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px);
background-size:
100px 100px,
100px 100px,
20px 20px,
20px 20px;
background-position:
-2px -2px,
-2px -2px,
-1px -1px,
-1px -1px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.spacer {
width: 100%;
height: 20vh;
display: flex;
align-items: center;
justify-content: center;
}
.main {
position: relative;
height: 200vh;
min-height: 800px;
--grid-line: rgba(255, 255, 255, 0.08);
--box-border: rgba(255, 255, 255, 0.25);
}
.container {
position: absolute;
width: 200px;
height: 200px;
display: flex;
flex-direction: column; /* Items untereinander */
align-items: center; /* horizontal zentrieren */
justify-content: center; /* vertikal zentrieren, kann auch flex-start sein */
}
.experience-text {
width: 200px;
text-align: center;
}
.experience-text h2 {
font-size: 1.2rem;
color: #7c7c6f;
margin: 0;
}
.initial {
left: 60%;
top: 0%;
}
.circle {
width: 100px;
height: 100px;
position: relative;
z-index: 10;
border-radius: 10px;
background-size: contain;
background-repeat: no-repeat;
background-color: transparent;
background-image: url("../../assets/bird-claw.svg");
}
.second {
left: 10%;
top: 50%;
}
.marker {
border-radius: 10px;
}
.second .marker {
width: 100px;
height: 100px;
}
.third {
right: 10%;
bottom: 3rem;
}
.third .marker {
width: 100px;
height: 100px;
}
.fourth {
left: 10%;
top: 750%;
}
.fourth .marker {
width: 100px;
height: 100px;
}
</style>