Implement GSAP Features in 'neler-yapariz-gsap' Template: Introduced a comprehensive set of GSAP animations and sections in the 'neler-yapariz-gsap' template, enhancing the visual dynamics of the page. This update includes new JavaScript and CSS files for various animations, such as flip, inertia, marquee, and scrolltrigger, along with a structured layout for improved user interaction. Additionally, localization support has been integrated for all text elements, ensuring a seamless experience for users across different languages.

This commit is contained in:
Ümit Tunç
2026-01-10 17:47:51 +03:00
parent 3ad69677d8
commit 2fdf187658
42 changed files with 1902 additions and 78 deletions
@@ -0,0 +1,60 @@
@extends('layouts.gsap', ['header' => 'partials.header', 'footer' => 'partials.footer'])
@section('title', t('Neler Yapıyoruz?') ?: 'Neler Yapıyoruz?')
@push('styles')
@include('templates.neler-yapariz.external-links')
<style>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/css/main.css')) !!}
</style>
<style>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/css/additional.css')) !!}
</style>
@endpush
@section('content')
@include('templates.neler-yapariz.navigation')
<div id="smooth-wrapper" data-start="hidden" class="scroll-wrapper">
<main id="smooth-content" class="main">
@include('templates.neler-yapariz.sections.hero')
@include('templates.neler-yapariz.sections.flip')
@include('templates.neler-yapariz.sections.slider')
@include('templates.neler-yapariz.sections.inertia')
@include('templates.neler-yapariz.sections.text')
@include('templates.neler-yapariz.sections.marquee')
</div>
@include('templates.neler-yapariz.sections.footer')
</main>
</div>
@endsection
@push('scripts')
@include('templates.neler-yapariz.external-scripts')
{{-- Navigation Scripts --}}
@include('templates.neler-yapariz.js.nav')
@include('templates.neler-yapariz.js.section-selector')
{{-- Hero Script --}}
@include('templates.neler-yapariz.js.hero')
{{-- Section Scripts --}}
@include('templates.neler-yapariz.js.flip')
@include('templates.neler-yapariz.js.section-scroll')
@include('templates.neler-yapariz.js.scrolltrigger')
@include('templates.neler-yapariz.js.slider')
@include('templates.neler-yapariz.js.inertia')
@include('templates.neler-yapariz.js.text')
@include('templates.neler-yapariz.js.marquee')
{{-- Footer Scripts --}}
@include('templates.neler-yapariz.js.footerlogo')
@include('templates.neler-yapariz.js.copybtn-buttons')
{{-- Global Scripts --}}
@include('templates.neler-yapariz.js.global')
@endpush
@@ -0,0 +1,128 @@
<script>
{
/** -- Copy Button */
const copybtn = () => {
const copybtn = [...document.querySelectorAll("[data-module='copybtn']")];
// Create a map to store data for each button
const buttonDataMap = new Map();
// Single event listener that checks which button's data to use
document.addEventListener("copy", (event) => {
const activeButtonData = buttonDataMap.get("active");
if (activeButtonData) {
event.preventDefault();
event.clipboardData.setData(
"application/json",
JSON.stringify(activeButtonData)
);
event.clipboardData.setData(
"text/plain",
JSON.stringify(activeButtonData)
);
buttonDataMap.delete("active"); // Clear after copying
}
});
copybtn.forEach((btn) => {
const url = btn.getAttribute("data-copy");
const text = btn.children[0].children[0];
const icon = btn.querySelector("svg");
let isAnimating = false;
btn.onmouseenter = async () => {
if (isAnimating) return;
isAnimating = true;
await gsap.to(icon, {
rotate: "+=360",
duration: 0.3,
ease: "expo.out",
});
isAnimating = false;
};
btn.onclick = async (evt) => {
try {
const res = await fetch(url);
let data = await res.text();
// Try to parse as JSON in case it's JSON data
try {
const jsonData = JSON.parse(data);
buttonDataMap.set("active", jsonData);
} catch {
buttonDataMap.set("active", data);
}
// Trigger the copy command
document.execCommand("copy");
text.textContent = "Copied!";
console.log("copied successfully");
setTimeout(() => {
text.textContent = "Copy this";
}, 1000);
} catch (error) {
console.error("Failed to copy:", error);
text.textContent = "Failed to copy";
setTimeout(() => {
text.textContent = "Copy this";
}, 1000);
}
};
});
};
/** -- Split Text Button */
const split = (text, type = "chars") => {
text.setAttribute("aria-label", text.textContent);
const splits = new SplitText(text, { type });
splits[type].forEach((char) => char.setAttribute("aria-hidden", "true"));
return splits[type];
};
const buttons = () => {
const buttons = [...document.querySelectorAll("[data-module='btn']")];
buttons.forEach((btn) => {
const overflow = btn.children[0];
const text = overflow.children[0];
overflow.appendChild(text.cloneNode(true));
const splitText1 = split(overflow.children[0], "chars");
const splitText2 = split(overflow.children[1], "chars");
const animation = {
yPercent: "-=100",
duration: 0.8,
ease: "expo.out",
stagger: 0.02,
};
btn.onmouseenter = () => {
gsap.to(splitText1, { ...animation, yPercent: -100 });
gsap.to(splitText2, { ...animation, yPercent: -100 });
};
btn.onmouseleave = () => {
gsap.to(splitText1, { ...animation, yPercent: 0 });
gsap.to(splitText2, { ...animation, yPercent: 0 });
};
});
};
/** -- Controller */
addEventListener("GSAPReady", (event) => {
copybtn();
// desktop only animations
if (window.matchMedia("(min-width: 1024px)").matches) {
buttons();
}
});
}
</script>
@@ -0,0 +1,32 @@
<script>
// https://codepen.io/GreenSock/pen/RwLepdQ?editors=1010
addEventListener("GSAPReady", (event) => {
const wrapper = document.querySelector("[data-animate='flip']");
const toggles = [...wrapper.querySelector("[data-flip='toggle']").children];
const items = wrapper.querySelector("[data-flip='item']");
// console.log("flip", wrapper, toggles, items);
const flipGridList = () => {
const state = Flip.getState(items.children);
items.classList.toggle("list");
Flip.from(state, {
duration: 0.8,
ease: "expo.out",
onComplete: () => {
ScrollTrigger.refresh();
}
});
};
toggles.forEach((toggle, index) => {
toggle.addEventListener("click", () => {
toggles[0].classList.toggle("current");
toggles[1].classList.toggle("current");
flipGridList();
});
});
});
</script>
@@ -0,0 +1,71 @@
<script>
{
addEventListener("GSAPReady", (event) => {
const wrapper = document.querySelector("[data-animate='footerlogo']");
if (!wrapper) return;
const paths = [...wrapper.querySelectorAll("path")].reverse();
const lastPath = paths[paths.length - 1];
// Configuration for the footer logo animation
const FOOTER_ANIMATION_CONFIG = {
STAGGER: 0.05,
VISIBILITY_DURATION: 0.1,
};
// Set initial state
gsap.set(paths, {
autoAlpha: 0,
});
const animateFooterLogo = () => {
// Reset the last path visibility before starting the animation
gsap.set(lastPath, { autoAlpha: 0 });
const tl = gsap.timeline();
paths.forEach((path, index) => {
const baseDelay = index * FOOTER_ANIMATION_CONFIG.STAGGER;
const isLastPath = index === paths.length - 1;
// Flash animation
tl.to(
path,
{
autoAlpha: 1,
duration: 0.1,
ease: "none",
},
baseDelay
);
// Only fade out if it's not the last path
if (!isLastPath) {
tl.to(
path,
{
autoAlpha: 0,
duration: 0.1,
ease: "none",
},
baseDelay + FOOTER_ANIMATION_CONFIG.VISIBILITY_DURATION
);
}
});
return tl;
};
// Create the scroll trigger
ScrollTrigger.create({
trigger: wrapper,
start: "top bottom",
end: "bottom top",
onEnter: () => animateFooterLogo(),
onEnterBack: () => animateFooterLogo(),
});
// console.log(event.detail);
});
}
</script>
@@ -0,0 +1,81 @@
<script>
{
let lenis;
const initScroll = () => {
lenis = new Lenis({});
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((time) => lenis.raf(time * 1000));
gsap.ticker.lagSmoothing(0);
};
function initGsapGlobal() {
/** Do everything that needs to happen
* before triggering all
* the gsap animations */
initScroll();
// match reduced motion media
// const media = gsap.matchMedia();
/** Send a custom
* event to all your
* gsap animations
* to start them */
const sendGsapEvent = () => {
window.dispatchEvent(
new CustomEvent("GSAPReady", {
detail: {
lenis,
},
})
);
};
// Check if fonts are already loaded
if (document.fonts.status === "loaded") {
sendGsapEvent();
} else {
document.fonts.ready.then(() => {
sendGsapEvent();
});
}
/** We need specific handling because the
* grid/list changes the scroll height of the whole container
*/
let resizeTimeout;
const onResize = () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
ScrollTrigger.refresh();
}, 50);
};
window.addEventListener("resize", () => onResize());
const resizeObserver = new ResizeObserver((entries) => onResize());
resizeObserver.observe(document.body);
queueMicrotask(() => {
gsap.to("[data-start='hidden']", {
autoAlpha: 1,
duration: 0.1,
delay: 0.2,
});
});
}
// this only for dev
const documentReady =
document.readyState === "complete" || document.readyState === "interactive";
if (documentReady) {
initGsapGlobal();
} else {
addEventListener("DOMContentLoaded", (event) => initGsapGlobal());
}
}
</script>
@@ -0,0 +1,265 @@
<script>
{
const split = (text, type = "chars") => {
// Handle both single elements and arrays of elements
const elements = Array.isArray(text) ? text : [text];
// Set aria labels
elements.forEach((element) => {
if (element && typeof element.setAttribute === "function") {
element.setAttribute("aria-label", element.textContent);
}
});
// Split text and set aria-hidden
const splits = new SplitText(text, { type });
splits[type].forEach((char) => {
if (char && typeof char.setAttribute === "function") {
char.setAttribute("aria-hidden", "true");
}
});
return splits[type];
};
/** -- Setup and Utils */
let titleSplit,
parSplit,
layerItems,
isIn = false;
const animateIn = async (delay = 0) => {
isIn = true;
animateStripesOut();
gsap.to(parSplit, {
autoAlpha: 1,
yPercent: 0,
duration: 0.8,
delay: 0.65,
ease: "expo.out",
stagger: {
each: 0.08,
},
});
await gsap.to(titleSplit.flat(), {
yPercent: 0,
duration: 1.2,
delay: delay,
ease: "expo.out",
stagger: {
each: 0.01,
from: "end",
},
});
};
const animateOut = async () => {
isIn = false;
animateStripesIn();
gsap.to(parSplit, {
autoAlpha: 0,
yPercent: 100,
duration: 0.8,
ease: "expo.out",
stagger: {
each: 0.08,
},
});
await gsap.to(titleSplit.flat(), {
yPercent: 110,
duration: 0.8,
ease: "expo.out",
delay: 0.1,
stagger: {
each: 0.01,
from: "center",
},
});
};
/** -- Scribble Animaiton */
let isScribbling = false;
const SCRIBBLE_CONFIG = {
ROTATION_RANGE: 20,
TIME_BETWEEN_SCRIBBLES: 0.015,
VISIBILITY_DURATION: 0.01,
REVERSE_ORDER: true,
};
const animateScribble = (scribble) => {
if (isScribbling) return;
isScribbling = true;
gsap.set(scribble, { autoAlpha: 0, rotation: 0 });
const tl = gsap.timeline();
const scribblesToAnimate = [...scribble].reverse();
scribblesToAnimate.forEach((item, index) => {
const randomRotation =
Math.random() * SCRIBBLE_CONFIG.ROTATION_RANGE -
SCRIBBLE_CONFIG.ROTATION_RANGE / 2;
const baseDelay = index * SCRIBBLE_CONFIG.TIME_BETWEEN_SCRIBBLES;
tl.add(
gsap.set(item, {
autoAlpha: 1,
rotation: randomRotation,
delay: baseDelay,
})
);
tl.add(
gsap.set(item, {
autoAlpha: 0,
delay: baseDelay + SCRIBBLE_CONFIG.VISIBILITY_DURATION,
})
);
});
tl.call(() => {
isScribbling = false;
});
};
// hero stripes animation
let heroStripes,
stripes,
stripesAnimation = null;
const calcX = (i) => {
return i % 2 === 0
? -heroStripes[i].scrollWidth
: heroStripes[i].scrollWidth;
};
const animateStripesIn = () => {
if (stripesAnimation) {
stripesAnimation.kill();
}
// play video on the hero
document.querySelector("video").play()
gsap.set(heroStripes, {
autoAlpha: 1,
x: (i) => calcX(i),
yPercent: (i) => (heroStripes.length / 2 - i) * 80,
});
gsap.set(stripes, {
rotation: (i) => Math.random() * 30,
ease: "expo.out",
});
stripesAnimation = gsap.to(heroStripes, {
x: 0,
delay: 0.2,
duration: (i) => Math.random() + 1.2,
ease: "expo.out",
});
};
const animateStripesOut = () => {
if (stripesAnimation) {
stripesAnimation.kill();
}
stripesAnimation = gsap.to(heroStripes, {
x: (i) => calcX(i),
duration: 0.8,
ease: "expo.out",
});
};
addEventListener("GSAPReady", (event) => {
const wrapper = document.querySelector("[data-module='hero']");
if (!wrapper) return;
const layer = wrapper.querySelector("[data-hero='layer']");
layerItems = layer.children;
const title = wrapper.querySelector("[data-hero='title']");
const toggle = wrapper.querySelector("[data-hero='toggle']");
const alpha = document.querySelectorAll("[data-hero='alpha']");
const par = document.querySelectorAll("[data-hero='par']");
const scribble = [
...document.querySelector("[data-hero='scribble']").children[0].children,
];
stripes = [...layer.children];
heroStripes = stripes.map((item) => item.children[0]);
gsap.set(heroStripes, { autoAlpha: 0 });
gsap.to(layer, {
yPercent: 10,
scrollTrigger: {
trigger: layer,
start: "top top",
end: "+=100%",
scrub: true,
},
});
// split
titleSplit = split(title.children, "chars");
parSplit = split(par, "lines");
// initial state
gsap.set(titleSplit.flat(), { yPercent: -110 });
gsap.set(layer, { autoAlpha: 1 });
gsap.set(toggle, { scale: 3, rotation: 360 });
gsap.set(parSplit, { autoAlpha: 0, yPercent: 100 });
gsap.set(alpha, { autoAlpha: 0, scale: 0.7 });
gsap.set(scribble, { autoAlpha: 0 });
animateIn(0.6);
gsap.to(toggle, {
scale: 1,
rotation: 0,
delay: 0,
duration: 1.2,
ease: "expo.inOut",
});
gsap.to(parSplit, {
autoAlpha: 1,
yPercent: 0,
duration: 0.8,
delay: 0.65,
ease: "expo.out",
stagger: {
each: 0.08,
},
});
gsap.to(alpha, {
autoAlpha: 1,
scale: 1,
duration: 0.8,
delay: 0.9,
ease: "expo.out",
});
toggle.querySelector("input").addEventListener("change", (event) => {
if (event.target.checked) {
animateOut();
} else {
animateIn();
}
});
toggle.onmouseenter = () => {
if (!isIn) return;
// console.log("mouseenter");
animateScribble(scribble);
};
});
}
</script>
@@ -0,0 +1,166 @@
<script>
{
/** Utility Functions */
const split = (text, type = "chars") => {
text.setAttribute("aria-label", text.textContent);
const splits = new SplitText(text, { type });
splits[type].forEach((char) => char.setAttribute("aria-hidden", "true"));
return splits[type];
};
const getParams = (item) => {
const { duration, delay, stagger, ease, type } = item.dataset;
const params = {
duration: 1.2,
delay: 0,
type: "chars",
};
if (duration) params.duration = parseFloat(duration);
if (delay) params.delay = parseFloat(delay);
if (type && (type === "chars" || type === "words" || type === "lines"))
params.type = type;
return params;
};
const baseAnimation = (item) => {
const params = getParams(item);
return {
duration: params.duration,
delay: params.delay,
ease: "expo.out",
// stagger each item so the letters come in one after the other
stagger: {
each: 0.04,
from: "start",
},
scrollTrigger: {
trigger: item,
// use scrolltrigger to trigger on enter and reset on exit
toggleActions: "play reset play reset",
},
};
};
/** (1) Split Reveal Animation */
function createSplitRevealAnimation(item) {
const params = getParams(item); // 1. get params from attributes
const text = split(item, params.type); // 2. split the text
item.style.overflow = "hidden"; // 3. set container to overflow
// 4. create the animation
return gsap.fromTo(
text,
{ yPercent: 120 },
{
...baseAnimation(item),
yPercent: 0,
}
);
}
function createScrambledAnimation(item) {
const text = item.textContent;
const randomText = Array(text.length)
.fill()
.map(() => String.fromCharCode(Math.floor(Math.random() * (90 - 65) + 65)))
.join("")
.toLowerCase();
return gsap.fromTo(
item.children[0],
{
scrambleText: randomText,
},
{
...baseAnimation(item),
scrambleText: text,
chars: text,
}
);
}
function createAlphaAnimation(item) {
const params = getParams(item); // 1. get params from attributes
const text = split(item, "chars"); // 2. split the text
return gsap.fromTo(
text,
{ autoAlpha: 0 },
{
...baseAnimation(item),
autoAlpha: 1,
stagger: {
each: 0.02,
from: "random",
},
}
);
}
function createSideAnimation(item) {
const params = getParams(item);
const outer = split(item, "chars");
outer.forEach((char) => {
char.style.overflow = "hidden";
});
const inner = split(item.children[0], "chars");
return gsap.fromTo(
inner,
{ x: 100 },
{
...baseAnimation(item),
x: 0,
stagger: {
each: 0.02,
from: "end",
},
}
);
}
function createUpDownAnimation(item) {
const params = getParams(item);
const outer = split(item, "chars");
outer.forEach((char) => {
char.style.overflow = "hidden";
});
const inner = split(item.children[0], "chars");
return gsap.fromTo(
inner,
{
yPercent: (i) => {
return i % 2 === 0 ? 100 : -100;
},
},
{
...baseAnimation(item),
yPercent: 0,
stagger: {
each: 0.02,
from: "random",
},
}
);
}
/** Main Text Effect Wrapper */
addEventListener("GSAPReady", (event) => {
const texts = [...document.querySelectorAll('[data-animate="text"]')];
texts.forEach((item) => {
if (item.dataset.type === "chars") createSplitRevealAnimation(item);
else if (item.dataset.type === "words") createSplitRevealAnimation(item);
else if (item.dataset.type === "scramble") createScrambledAnimation(item);
else if (item.dataset.type === "alpha") createAlphaAnimation(item);
else if (item.dataset.type === "side") createSideAnimation(item);
else if (item.dataset.type === "updown") createUpDownAnimation(item);
});
});
}
</script>
@@ -0,0 +1,32 @@
<script>
addEventListener("GSAPReady", (event) => {
// console.log("marquee");
const wrapper = document.querySelector("[data-animate='marquee']");
if (!wrapper) return;
const sections = [...wrapper.querySelectorAll("[data-marquee='line']")];
gsap.fromTo(
sections,
{
x: (i) =>
i % 2 === 0
? sections[i].offsetWidth / 4
: -sections[i].offsetWidth / 4,
},
{
x: (i) =>
i % 2 === 0
? -sections[i].offsetWidth / 4
: sections[i].offsetWidth / 4,
scrollTrigger: {
trigger: wrapper,
start: "top bottom",
end: "bottom top",
scrub: true,
// invalidateOnRefresh: true,
},
}
);
});
</script>
@@ -0,0 +1,46 @@
<script>
{
const params = {
duration: 0.8,
ease: "expo.out",
};
const handleSecondaryVisibility = (secondary) => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
gsap.to(secondary, {
yPercent: 200,
...params,
});
} else {
gsap.to(secondary, {
yPercent: 0,
...params,
});
}
});
},
{
threshold: 0.02,
rootMargin: "-10% 0px",
}
);
const contentElement = document.getElementById("content");
if (contentElement) {
observer.observe(contentElement);
}
};
addEventListener("GSAPReady", (event) => {
const wrapper = document.querySelector("[data-module='nav']");
if (!wrapper) return;
const main = wrapper.children[0];
const secondary = wrapper.children[1].children[0];
handleSecondaryVisibility(secondary);
});
}
</script>
@@ -0,0 +1,110 @@
<script>
const split = (text, type = "chars") => {
text.setAttribute("aria-label", text.textContent);
const splits = new SplitText(text, { type });
splits[type].forEach((char) => char.setAttribute("aria-hidden", "true"));
return splits[type];
};
addEventListener("GSAPReady", (event) => {
const section = document.querySelector("[data-animate='videogrow']");
const video = section.querySelector("[data-videogrow='video']");
const img = video.children[0];
const title = split(
section.querySelector("[data-videogrow='title']"),
"chars"
);
const tl = gsap.timeline({
scrollTrigger: {
trigger: section,
start: "top center",
end: "bottom bottom+=100%",
invalidateOnRefresh: true,
scrub: 1,
},
});
gsap.set(
title,
{
scale: 0,
rotation: (i) => Math.random() * 360 - 180,
})
tl.to(
title,
{
scale: 1,
duration: 0.2,
rotation: 0,
ease: "expo.out",
stagger: {
each: 0.05,
from: "random",
},
}
);
tl.fromTo(
video,
{
clipPath: "inset(10% 50% 10% 50%)",
yPercent: 100,
},
{
ease: "power3",
clipPath: "inset(0% 0% 0% 0%)",
duration: 1,
yPercent: 0,
},
".3"
);
tl.fromTo(
video,
{
scale: 0.5,
// rotation: 180,
},
{
ease: "back.inOut(.2)",
scale: 1,
duration: 0.8,
// rotation: 0,
},
"<"
);
tl.fromTo(
img,
{
scale: 2.8,
yPercent: 40,
},
{
scale: 1.2,
duration: 0.8,
delay: 0.2,
yPercent: 0,
},
"<"
);
tl.to(video, {
scale: 0.9,
ease: "linear",
});
tl.to(
img,
{
scale: 1,
ease: "linear",
},
"<"
);
});
</script>
@@ -0,0 +1,97 @@
asdsada<nav class="hr-bottom">
<button id="section1Btn">Section 1</button>
<button id="section2Btn">Section 2</button>
<button id="section3Btn">Section 3</button>
</nav>
<h2 class="heading-scroll heading-l" id="section1">Section 1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nibh quam, egestas eu eros molestie, eleifend viverra augue. Suspendisse potenti. Quisque commodo consectetur quam, non pretium orci viverra at. Maecenas eget iaculis nunc. </p>
<p>Praesent at pellentesque augue. Nunc sed ullamcorper risus. Duis tincidunt consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<p>Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<p>consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa.</p>
<p>Praesent at pellentesque augue. Nunc sed ullamcorper risus. Duis tincidunt consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<p>consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa.</p>
<p>Praesent at pellentesque augue. Nunc sed ullamcorper risus. Duis tincidunt consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<p>consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa.</p>
<p>Praesent at pellentesque augue. Nunc sed ullamcorper risus. Duis tincidunt consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<h2 class="heading-scroll heading-l" id="section2">Section 2</h2>
<p>consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa.</p>
<p>Praesent at pellentesque augue. Nunc sed ullamcorper risus. Duis tincidunt consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<h2 class="heading-scroll heading-l" id="section3">Section 3</h2>
<p>Praesent at pellentesque augue. Nunc sed ullamcorper risus. Duis tincidunt consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementes, nascetur ridiculus mus.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nibh quam, egestas eu eros molestie, eleifend viverra augue. Suspendisse potenti. Quisque commodo consectetur quam, non pretium orci viverra at. Maecenas eget iaculis nunc. </p>
<p>Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa.</p>
<p>consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa.</p>
<p>Praesent at pellentesque augue. Nunc sed ullamcorper risus. Duis tincidunt consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<p>consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa.</p>
<p>Praesent at pellentesque augue. Nunc sed ullamcorper risus. Duis tincidunt consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<p>consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa.</p>
<p>Praesent at pellentesque augue. Nunc sed ullamcorper risus. Duis tincidunt consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<p>consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa.</p>
<p>Praesent at pellentesque augue. Nunc sed ullamcorper risus. Duis tincidunt consectetur condimentum. Suspendisse pharetra purus urna, ac pretium mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<p>Mi elementum et. Praesent dui nibh, ullamcorper in justo sed, volutpat cursus orci. Etiam vitae sodales massa. Cum sociis natoque penatibus et magnis dis parturient montes,</p>
<style>
/* Global styles come from external css */
body {
margin: 0;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.content {
margin: 20px;
padding-top: 4rem;
width: 100%;
max-width: 80ch;
}
nav {
position: fixed;
top: 0;
width: 100%;
background: var(--color-just-black);
margin: 0;
padding: 1rem 10px;
display: flex;
justify-content: space-around;
}
h2 {
color: var(--color-surface-white);
font-size: 2rem;
margin-top: 4rem;
}
button {
border-color: transparent;
}
button:hover {
border-color: transparent;
}
</style>
<script>
document.querySelectorAll("nav button").forEach((btn, index) => {
btn.addEventListener("click", () => {
gsap.to(window, {duration: 1, scrollTo:{y:"#section" + (index + 1), offsetY:120}});
});
});
</script>
@@ -0,0 +1,95 @@
<script>
{
/** Section Selector */
const createObserver = (section, cb) => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && entry.intersectionRatio >= 0.1) {
cb(entry.target);
}
});
}, {
threshold: 0.2 // This means the callback will fire when at least 10% is visible
});
observer.observe(section);
};
addEventListener("GSAPReady", (event) => {
const { lenis } = event.detail;
const wrapper = document.querySelector("[data-animate='sectionselector']");
const items = [...wrapper.children];
const highlight = wrapper.querySelector("[data-selector='highlight']");
let currentIndex = 0;
const sections = [...document.querySelectorAll("section")];
// Navigation height'ini hesapla (logo height'i ve üst/alt boşluklar için)
const navWrapper = document.querySelector("[data-module='nav']");
const navElement = navWrapper?.querySelector(".nav");
const logoElement = navWrapper?.querySelector(".logo-banner-w");
const getNavHeight = () => {
if (navWrapper && navElement) {
// Navigation element'inin toplam height'ini al (padding dahil)
const navHeight = navElement.offsetHeight;
// Logo element'inin üstündeki boşluğu hesapla
if (logoElement) {
const logoRect = logoElement.getBoundingClientRect();
const navRect = navElement.getBoundingClientRect();
const topSpace = logoRect.top - navRect.top;
// Logo height'i + üstündeki boşluk + altındaki boşluk
return navHeight + topSpace;
}
return navHeight;
}
return 0;
};
sections.forEach((section, index) => {
createObserver(section, () => {
items[currentIndex].classList.remove("current");
currentIndex = index;
items[currentIndex].classList.add("current");
moveHighlightTo(index);
});
});
let flipAnimation = null
const moveHighlightTo = (index) => {
const state = Flip.getState(highlight);
items[index].appendChild(highlight);
if (flipAnimation) flipAnimation.kill()
flipAnimation = Flip.from(state, {
duration: 0.5,
ease: "expo.out",
});
};
items.forEach((item, index) => {
item.addEventListener("click", () => {
const targetSection = document.getElementById(items[index].dataset.to);
if (targetSection) {
const navHeight = getNavHeight();
lenis.scrollTo(targetSection, {
offset: -navHeight
});
} else {
lenis.scrollTo("#" + items[index].dataset.to);
}
});
item.addEventListener("mouseenter", () => {
moveHighlightTo(index);
});
item.addEventListener("mouseleave", () => {
moveHighlightTo(currentIndex);
});
});
});
}
</script>
@@ -0,0 +1,380 @@
<script>
// https://codepen.io/GreenSock/pen/gOvvJee?editors=1010
// https://gsap.com/docs/v3/HelperFunctions/helpers/seamlessLoop/
// https://codepen.io/GreenSock/pen/gOvvJee?editors=1010
// https://gsap.com/docs/v3/HelperFunctions/helpers/seamlessLoop/
function horizontalLoop(items, config) {
let timeline;
items = gsap.utils.toArray(items);
config = config || {};
gsap.context(() => {
// use a context so that if this is called from within another context or a gsap.matchMedia(), we can perform proper cleanup like the "resize" event handler on the window
let onChange = config.onChange,
lastIndex = 0,
tl = gsap.timeline({
repeat: config.repeat,
onUpdate:
onChange &&
function () {
let i = tl.closestIndex();
if (lastIndex !== i) {
lastIndex = i;
onChange(items[i], i);
}
},
paused: config.paused,
defaults: { ease: "none" },
onReverseComplete: () =>
tl.totalTime(tl.rawTime() + tl.duration() * 100),
}),
length = items.length,
startX = items[0].offsetLeft,
times = [],
widths = [],
spaceBefore = [],
xPercents = [],
curIndex = 0,
indexIsDirty = false,
center = config.center,
pixelsPerSecond = (config.speed || 1) * 100,
snap =
config.snap === false ? (v) => v : gsap.utils.snap(config.snap || 1), // some browsers shift by a pixel to accommodate flex layouts, so for example if width is 20% the first element's width might be 242px, and the next 243px, alternating back and forth. So we snap to 5 percentage points to make things look more natural
timeOffset = 0,
container =
center === true
? items[0].parentNode
: gsap.utils.toArray(center)[0] || items[0].parentNode,
totalWidth,
getTotalWidth = () =>
items[length - 1].offsetLeft +
(xPercents[length - 1] / 100) * widths[length - 1] -
startX +
spaceBefore[0] +
items[length - 1].offsetWidth *
gsap.getProperty(items[length - 1], "scaleX") +
(parseFloat(config.paddingRight) || 0),
populateWidths = () => {
let b1 = container.getBoundingClientRect(),
b2;
// Reset all items to their natural position first
gsap.set(items, {
x: 0,
xPercent: 0,
clearProps: "transform",
});
// Force a reflow
items[0].offsetWidth;
// Get the container's new position after reset
startX = items[0].offsetLeft;
items.forEach((el, i) => {
// Get the natural width without any transforms
widths[i] = el.offsetWidth;
// Calculate the space between items
b2 = el.getBoundingClientRect();
spaceBefore[i] = b2.left - (i ? b1.right : b1.left);
b1 = b2;
// Reset xPercent to 0 for accurate calculations
xPercents[i] = 0;
});
// Set all items to their calculated positions
gsap.set(items, {
xPercent: (i) => xPercents[i],
});
// Calculate total width after all items are positioned
totalWidth = getTotalWidth();
},
timeWrap,
populateOffsets = () => {
timeOffset = center
? (tl.duration() * (container.offsetWidth / 2)) / totalWidth
: 0;
center &&
times.forEach((t, i) => {
times[i] = timeWrap(
tl.labels["label" + i] +
(tl.duration() * widths[i]) / 2 / totalWidth -
timeOffset
);
});
},
getClosest = (values, value, wrap) => {
let i = values.length,
closest = 1e10,
index = 0,
d;
while (i--) {
d = Math.abs(values[i] - value);
if (d > wrap / 2) {
d = wrap - d;
}
if (d < closest) {
closest = d;
index = i;
}
}
return index;
},
populateTimeline = () => {
let i, item, curX, distanceToStart, distanceToLoop;
tl.clear();
for (i = 0; i < length; i++) {
item = items[i];
curX = (xPercents[i] / 100) * widths[i];
distanceToStart = item.offsetLeft + curX - startX + spaceBefore[0];
distanceToLoop =
distanceToStart + widths[i] * gsap.getProperty(item, "scaleX");
tl.to(
item,
{
xPercent: snap(((curX - distanceToLoop) / widths[i]) * 100),
duration: distanceToLoop / pixelsPerSecond,
},
0
)
.fromTo(
item,
{
xPercent: snap(
((curX - distanceToLoop + totalWidth) / widths[i]) * 100
),
},
{
xPercent: xPercents[i],
duration:
(curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond,
immediateRender: false,
},
distanceToLoop / pixelsPerSecond
)
.add("label" + i, distanceToStart / pixelsPerSecond);
times[i] = distanceToStart / pixelsPerSecond;
}
timeWrap = gsap.utils.wrap(0, tl.duration());
},
refresh = (deep) => {
let progress = tl.progress();
tl.progress(0, true);
// Reset only the x transforms while preserving other properties
gsap.set(items, {
x: 0,
xPercent: 0,
});
// Force a reflow
items[0].offsetWidth;
populateWidths();
deep && populateTimeline();
populateOffsets();
if (deep && tl.draggable && tl.paused()) {
tl.time(times[curIndex], true);
} else {
tl.progress(progress, true);
}
},
onResize = () => {
if (window.resizeTimeout) clearTimeout(window.resizeTimeout);
window.resizeTimeout = setTimeout(() => {
refresh(true);
}, 100);
},
proxy;
gsap.set(items, { x: 0 });
populateWidths();
populateTimeline();
populateOffsets();
window.addEventListener("resize", onResize);
function toIndex(index, vars) {
vars = vars || {};
Math.abs(index - curIndex) > length / 2 &&
(index += index > curIndex ? -length : length); // always go in the shortest direction
let newIndex = gsap.utils.wrap(0, length, index),
time = times[newIndex];
if (time > tl.time() !== index > curIndex && index !== curIndex) {
// if we're wrapping the timeline's playhead, make the proper adjustments
time += tl.duration() * (index > curIndex ? 1 : -1);
}
if (time < 0 || time > tl.duration()) {
vars.modifiers = { time: timeWrap };
}
curIndex = newIndex;
vars.overwrite = true;
gsap.killTweensOf(proxy);
return vars.duration === 0
? tl.time(timeWrap(time))
: tl.tweenTo(time, vars);
}
tl.toIndex = (index, vars) => toIndex(index, vars);
tl.closestIndex = (setCurrent) => {
let index = getClosest(times, tl.time(), tl.duration());
if (setCurrent) {
curIndex = index;
indexIsDirty = false;
}
return index;
};
tl.current = () => (indexIsDirty ? tl.closestIndex(true) : curIndex);
tl.next = (vars) => toIndex(tl.current() + 1, vars);
tl.previous = (vars) => toIndex(tl.current() - 1, vars);
tl.times = times;
tl.progress(1, true).progress(0, true); // pre-render for performance
if (config.reversed) {
tl.vars.onReverseComplete();
tl.reverse();
}
if (config.draggable && typeof Draggable === "function") {
proxy = document.createElement("div");
let wrap = gsap.utils.wrap(0, 1),
ratio,
startProgress,
draggable,
dragSnap,
lastSnap,
initChangeX,
wasPlaying,
align = () =>
tl.progress(
wrap(startProgress + (draggable.startX - draggable.x) * ratio)
),
syncIndex = () => tl.closestIndex(true);
typeof InertiaPlugin === "undefined" &&
console.warn(
"InertiaPlugin required for momentum-based scrolling and snapping. https://greensock.com/club"
);
draggable = Draggable.create(proxy, {
trigger: items[0].parentNode,
type: "x",
onPressInit() {
let x = this.x;
gsap.killTweensOf(tl);
wasPlaying = !tl.paused();
tl.pause();
startProgress = tl.progress();
refresh();
ratio = 1 / totalWidth;
initChangeX = startProgress / -ratio - x;
gsap.set(proxy, { x: startProgress / -ratio });
},
onDrag: align,
onThrowUpdate: align,
overshootTolerance: 0,
inertia: true,
snap(value) {
//note: if the user presses and releases in the middle of a throw, due to the sudden correction of proxy.x in the onPressInit(), the velocity could be very large, throwing off the snap. So sense that condition and adjust for it. We also need to set overshootTolerance to 0 to prevent the inertia from causing it to shoot past and come back
if (Math.abs(startProgress / -ratio - this.x) < 10) {
return lastSnap + initChangeX;
}
let time = -(value * ratio) * tl.duration(),
wrappedTime = timeWrap(time),
snapTime = times[getClosest(times, wrappedTime, tl.duration())],
dif = snapTime - wrappedTime;
Math.abs(dif) > tl.duration() / 2 &&
(dif += dif < 0 ? tl.duration() : -tl.duration());
lastSnap = (time + dif) / tl.duration() / -ratio;
return lastSnap;
},
onRelease() {
syncIndex();
draggable.isThrowing && (indexIsDirty = true);
},
onThrowComplete: () => {
syncIndex();
wasPlaying && tl.play();
},
})[0];
tl.draggable = draggable;
}
tl.closestIndex(true);
lastIndex = curIndex;
onChange && onChange(items[curIndex], curIndex);
timeline = tl;
return () => window.removeEventListener("resize", onResize); // cleanup
});
return timeline;
}
/* -- Global Params */
const sliderParams = {
duration: 0.5,
ease: "power2.out",
};
addEventListener("GSAPReady", (event) => {
const wrapper = document.querySelector("[data-animate='slider']");
const slides = [...wrapper.querySelector("[data-slider='slides']").children];
/* -- Setup Slider UI */
const progress = wrapper.querySelector("[data-slider='progress']");
const next = wrapper.querySelector("[data-slider='next']");
const prev = wrapper.querySelector("[data-slider='prev']");
let currentIndex = 0;
const dots = [...wrapper.querySelector("[data-slider='dots']").children].map(
(item, index) => {
const btn = item.children[0];
btn.addEventListener("click", () => {
loop.toIndex(index, sliderParams);
});
return btn;
}
);
/* -- Helper Functions */
const updateCurrent = (index) => {
// handle dots
dots[currentIndex].classList.remove("current");
dots[index].classList.add("current");
slides[currentIndex].classList.remove("current");
slides[index].classList.add("current");
// handle slides
// ...
gsap.to(progress.children[0], {
width: `${(index / (slides.length - 1)) * 100}%`,
duration: 0.6,
ease: "expo.out",
});
// save the previous position
currentIndex = index;
};
/* -- Setup Slider */
let loop;
setTimeout(() => {
loop = horizontalLoop(slides, {
paused: true,
draggable: true,
// draggableOptions: {
// dragResistance: 10,
// resistance: 10,
// },
center: true,
onChange: (element, index) => {
updateCurrent(index);
},
});
}, 500);
// (*) THIS IS JUST TO CHECK PLEASE REMOVE
next.addEventListener("click", () => {
loop.next(sliderParams);
});
prev.addEventListener("click", () => {
loop.previous(sliderParams);
});
});
</script>
@@ -0,0 +1,167 @@
<script>
{
/** Utility Functions */
const split = (text, type = "chars") => {
text.setAttribute("aria-label", text.textContent);
const splits = new SplitText(text, { type });
splits[type].forEach((char) => char.setAttribute("aria-hidden", "true"));
return splits[type];
};
const getParams = (item) => {
const { duration, delay, stagger, ease, type } = item.dataset;
const params = {
duration: 1.2,
delay: 0,
type: "chars",
};
if (duration) params.duration = parseFloat(duration);
if (delay) params.delay = parseFloat(delay);
if (type && (type === "chars" || type === "words" || type === "lines"))
params.type = type;
return params;
};
const baseAnimation = (item) => {
const params = getParams(item);
return {
duration: params.duration,
delay: params.delay,
ease: "expo.out",
// stagger each item so the letters come in one after the other
stagger: {
each: 0.04,
from: "start",
},
scrollTrigger: {
trigger: item,
// use scrolltrigger to trigger on enter and reset on exit
toggleActions: "play reset play reset",
},
};
};
/** (1) Split Reveal Animation */
function createSplitRevealAnimation(item) {
const params = getParams(item); // 1. get params from attributes
const text = split(item, params.type); // 2. split the text
item.style.overflow = "hidden"; // 3. set container to overflow
// 4. create the animation
return gsap.fromTo(
text,
{ yPercent: 120 },
{
...baseAnimation(item),
yPercent: 0,
}
);
}
function createScrambledAnimation(item) {
const text = item.textContent;
const randomText = Array(text.length)
.fill()
.map(() => String.fromCharCode(Math.floor(Math.random() * (90 - 65) + 65)))
.join("")
.toLowerCase();
return gsap.fromTo(
item.children[0],
{
scrambleText: randomText,
},
{
...baseAnimation(item),
scrambleText: text,
chars: text,
}
);
}
function createAlphaAnimation(item) {
const params = getParams(item); // 1. get params from attributes
const text = split(item, "chars"); // 2. split the text
return gsap.fromTo(
text,
{ autoAlpha: 0 },
{
...baseAnimation(item),
autoAlpha: 1,
stagger: {
each: 0.02,
from: "random",
},
}
);
}
function createSideAnimation(item) {
const params = getParams(item);
const outer = split(item, "chars");
outer.forEach((char) => {
char.style.overflow = "hidden";
});
const inner = split(item.children[0], "chars");
return gsap.fromTo(
inner,
{ x: 100 },
{
...baseAnimation(item),
x: 0,
stagger: {
each: 0.02,
from: "end",
},
}
);
}
function createUpDownAnimation(item) {
const params = getParams(item);
const outer = split(item, "chars");
outer.forEach((char) => {
char.style.overflow = "hidden";
});
const inner = split(item.children[0], "chars");
return gsap.fromTo(
inner,
{
yPercent: (i) => {
return i % 2 === 0 ? 100 : -100;
},
},
{
...baseAnimation(item),
yPercent: 0,
stagger: {
each: 0.02,
from: "random",
},
}
);
}
/** Main Text Effect Wrapper */
addEventListener("GSAPReady", (event) => {
const texts = [...document.querySelectorAll('[data-animate="text"]')];
texts.forEach((item) => {
if (item.dataset.type === "chars") createSplitRevealAnimation(item);
else if (item.dataset.type === "words") createSplitRevealAnimation(item);
else if (item.dataset.type === "scramble") createScrambledAnimation(item);
else if (item.dataset.type === "alpha") createAlphaAnimation(item);
else if (item.dataset.type === "side") createSideAnimation(item);
else if (item.dataset.type === "updown") createUpDownAnimation(item);
});
});
}
</script>
@@ -1,82 +1,10 @@
@extends('layouts.gsap', ['header' => 'partials.header', 'footer' => 'partials.footer']) <?php $headerTemplate = 'Blog Header'; ?>
@extends('layouts.site', ['header' => 'partials.header', 'footer' => 'partials.footer'])
@section('title', t('Neler Yapıyoruz?') ?: 'Neler Yapıyoruz?') @section('title', 'Anasayfa')
@push('styles')
@include('templates.neler-yapariz.external-links')
<style>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/css/main.css')) !!}
</style>
<style>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/css/additional.css')) !!}
</style>
@endpush
@section('content') @section('content')
@include('templates.neler-yapariz.navigation') @include('templates.neler-yapariz.hero')
<div id="smooth-wrapper" data-start="hidden" class="scroll-wrapper"> @include('templates.home.contact')
<main id="smooth-content" class="main">
@include('templates.neler-yapariz.sections.hero')
@include('templates.neler-yapariz.sections.flip')
@include('templates.neler-yapariz.sections.slider')
@include('templates.neler-yapariz.sections.inertia')
@include('templates.neler-yapariz.sections.text')
@include('templates.neler-yapariz.sections.marquee')
</div>
@include('templates.neler-yapariz.sections.footer')
</main>
</div>
@endsection @endsection
@push('scripts')
@include('templates.neler-yapariz.external-scripts')
{{-- Navigation Scripts --}}
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/nav.js')) !!}
</script>
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/section-selector.js')) !!}
</script>
{{-- Hero Script --}}
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/hero.js')) !!}
</script>
{{-- Section Scripts --}}
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/flip.js')) !!}
</script>
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/scrolltrigger.js')) !!}
</script>
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/slider.js')) !!}
</script>
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/inertia.js')) !!}
</script>
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/text.js')) !!}
</script>
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/marquee.js')) !!}
</script>
{{-- Footer Scripts --}}
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/footerlogo.js')) !!}
</script>
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/copybtn-buttons.js')) !!}
</script>
{{-- Global Scripts --}}
<script>
{!! file_get_contents(resource_path('views/templates/neler-yapariz/js/global.js')) !!}
</script>
@endpush
@@ -0,0 +1,166 @@
<section class="wrapper !bg-[#edf2fc]">
<div class="container pt-10 pb-36 xl:pt-[4.5rem] lg:pt-[4.5rem] md:pt-[4.5rem] xl:pb-40 lg:pb-40 md:pb-40 !text-center">
<div class="flex flex-wrap mx-[-15px]">
<div class="md:w-8/12 lg:w-7/12 xl:w-6/12 xxl:w-5/12 w-full flex-[0_0_auto] !px-[15px] max-w-full !mx-auto !mb-12">
<h1 class="!text-[calc(1.365rem_+_1.38vw)] font-bold !leading-[1.2] xl:!text-[2.4rem] !mb-3">{{ t('neler-yapariz.hero.title') }}</h1>
<p class="lead !leading-[1.65] text-[0.9rem] font-medium lg:!px-7 xl:!px-7 xxl:!px-6">{{ t('neler-yapariz.hero.subtitle') }} <span class="relative z-[2] whitespace-nowrap after:content-[''] after:block after:absolute after:w-[102.5%] after:h-[30%] after:left-[-1.5%] after:z-[-1] after:transition-all after:duration-[0.2s] after:ease-in-out after:!mt-0 after:rounded-[5rem] after:bottom-[9%] motion-reduce:after:transition-none after:bg-[rgba(63,120,224,.12)]">{{ t('neler-yapariz.hero.highlight') }}</span> {{ t('neler-yapariz.hero.subtitle_end') }}</p>
</div>
<!-- /column -->
</div>
<!-- /.row -->
</div>
<!-- /.container -->
</section>
<section class="wrapper !bg-[#ffffff] angled upper-end !relative border-0 before:top-[-4rem] before:border-l-transparent before:border-r-[100vw] before:border-t-[4rem] before:border-[#fefefe] before:content-[''] before:block before:absolute before:z-0 before:!border-y-transparent before:border-0 before:border-solid before:right-0 after:top-[-4rem] after:border-l-transparent after:border-r-[100vw] after:border-t-[4rem] after:border-[#fefefe] after:content-[''] after:block after:absolute after:z-0 after:!border-y-transparent after:border-0 after:border-solid after:right-0">
<div class="container !pb-[4.5rem] xl:!pb-24 lg:!pb-24 md:!pb-24">
<div class="flex flex-wrap mx-[-15px] !mb-8">
<div class="w-full flex-[0_0_auto] !px-[15px] max-w-full !mt-[-10rem]">
<figure class="rounded-[0.4rem]"><img class="rounded-[0.4rem]" src="{{ asset('html/assets/img/photos/about5.jpg') }}" alt="{{ t('neler-yapariz.image_alt') }}"></figure>
<div class="flex flex-wrap mx-[-15px]">
<div class="xl:w-10/12 w-full flex-[0_0_auto] !px-[15px] max-w-full !mx-auto">
<div class="card image-wrapper bg-full bg-image bg-overlay bg-overlay-400 !text-white !mt-[-1.25rem] xl:!mt-0 lg:!mt-0 xl:-translate-y-2/4 lg:-translate-y-2/4 bg-cover [background-size:100%] bg-[center_center] bg-no-repeat !bg-scroll !relative z-0 before:rounded-[0.4rem] before:bg-[rgba(30,34,40,.4)] before:content-[''] before:block before:absolute before:z-[1] before:w-full before:h-full before:left-0 before:top-0" data-image-src="{{ asset('html/assets/img/photos/bg3.jpg') }}" style="background-image: url('{{ asset('html/assets/img/photos/bg3.jpg') }}');">
<div class="card-body p-[2.25rem] xl:!p-[2.5rem]">
<div class="flex flex-wrap mx-[-15px] items-center counter-wrapper !mt-[-20px] !text-center">
<div class="w-6/12 xl:w-3/12 lg:w-3/12 flex-[0_0_auto] !px-[15px] max-w-full !mt-[20px]">
<h3 class="counter counter-lg !text-white xl:!text-[2.2rem] !text-[calc(1.345rem_+_1.14vw)] !tracking-[normal] !leading-none !mb-2" style="visibility: visible;">7518</h3>
<p class="!text-[0.8rem] font-medium !mb-0 !text-white">{{ t('neler-yapariz.stats.completed_projects') }}</p>
</div>
<!--/column -->
<div class="w-6/12 xl:w-3/12 lg:w-3/12 flex-[0_0_auto] !px-[15px] max-w-full !mt-[20px]">
<h3 class="counter counter-lg !text-white xl:!text-[2.2rem] !text-[calc(1.345rem_+_1.14vw)] !tracking-[normal] !leading-none !mb-2" style="visibility: visible;">3472</h3>
<p class="!text-[0.8rem] font-medium !mb-0 !text-white">{{ t('neler-yapariz.stats.satisfied_customers') }}</p>
</div>
<!--/column -->
<div class="w-6/12 xl:w-3/12 lg:w-3/12 flex-[0_0_auto] !px-[15px] max-w-full !mt-[20px]">
<h3 class="counter counter-lg !text-white xl:!text-[2.2rem] !text-[calc(1.345rem_+_1.14vw)] !tracking-[normal] !leading-none !mb-2" style="visibility: visible;">2184</h3>
<p class="!text-[0.8rem] font-medium !mb-0 !text-white">{{ t('neler-yapariz.stats.expert_employees') }}</p>
</div>
<!--/column -->
<div class="w-6/12 xl:w-3/12 lg:w-3/12 flex-[0_0_auto] !px-[15px] max-w-full !mt-[20px]">
<h3 class="counter counter-lg !text-white xl:!text-[2.2rem] !text-[calc(1.345rem_+_1.14vw)] !tracking-[normal] !leading-none !mb-2" style="visibility: visible;">4523</h3>
<p class="!text-[0.8rem] font-medium !mb-0 !text-white">{{ t('neler-yapariz.stats.awards_won') }}</p>
</div>
<!--/column -->
</div>
<!--/.row -->
</div>
<!--/.card-body -->
</div>
<!--/.card -->
</div>
<!-- /column -->
</div>
<!-- /.row -->
</div>
<!-- /column -->
</div>
<!-- /.row -->
<div class="flex flex-wrap mx-[-15px] xl:mx-[-20px] lg:mx-[-20px] !mt-[25px] md:!mt-[4.5rem] lg:!mt-0 xl:!mt-0 !mb-20 items-center">
<div class="xl:w-6/12 lg:w-6/12 w-full flex-[0_0_auto] px-[20px] !mt-[40px] max-w-full xl:!order-2 lg:!order-2">
<div class="flex flex-wrap mx-[-15px] xl:mx-[-12.5px] lg:mx-[-12.5px] md:mx-[-12.5px] !mt-[-25px]">
<div class="xl:w-4/12 lg:w-4/12 md:w-4/12 w-full flex-[0_0_auto] !px-[15px] max-w-full xl:!ml-[16.66666667%] lg:!ml-[16.66666667%] md:!ml-[16.66666667%] !self-end !mt-[25px]">
<figure class="rounded-[0.4rem]"><img class="rounded-[0.4rem]" src="{{ asset('html/assets/img/photos/g1.jpg') }}" alt="{{ t('neler-yapariz.gallery.image_1_alt') }}"></figure>
</div>
<!--/column -->
<div class="xl:w-6/12 lg:w-6/12 md:w-6/12 w-full flex-[0_0_auto] px-[12.5px] max-w-full !self-end !mt-[25px]">
<figure class="rounded-[0.4rem]"><img class="rounded-[0.4rem]" src="{{ asset('html/assets/img/photos/g2.jpg') }}" alt="{{ t('neler-yapariz.gallery.image_2_alt') }}"></figure>
</div>
<!--/column -->
<div class="xl:w-6/12 lg:w-6/12 md:w-6/12 w-full flex-[0_0_auto] px-[12.5px] max-w-full xl:!ml-[8.33333333%] lg:!ml-[8.33333333%] md:!ml-[8.33333333%] !mt-[25px]">
<figure class="rounded-[0.4rem]"><img class="rounded-[0.4rem]" src="{{ asset('html/assets/img/photos/g3.jpg') }}" alt="{{ t('neler-yapariz.gallery.image_3_alt') }}"></figure>
</div>
<!--/column -->
<div class="xl:w-4/12 lg:w-4/12 md:w-4/12 w-full flex-[0_0_auto] !px-[15px] max-w-full !self-start !mt-[25px]">
<figure class="rounded-[0.4rem]"><img class="rounded-[0.4rem]" src="{{ asset('html/assets/img/photos/g4.jpg') }}" alt="{{ t('neler-yapariz.gallery.image_4_alt') }}"></figure>
</div>
<!--/column -->
</div>
<!--/.row -->
</div>
<!--/column -->
<div class="xl:w-6/12 lg:w-6/12 w-full flex-[0_0_auto] xl:!px-[20px] lg:!px-[20px] !px-[15px] !mt-[40px] max-w-full">
<h2 class="!text-[calc(1.305rem_+_0.66vw)] font-bold xl:!text-[1.8rem] !leading-[1.3] !mb-3">{{ t('neler-yapariz.what_we_do.title') }}</h2>
<p class="lead !mb-8 xxl:!pr-2 !text-[1.05rem] !leading-[1.6]">{{ t('neler-yapariz.what_we_do.description') }} <span class="relative z-[2] whitespace-nowrap after:content-[''] after:block after:absolute after:w-[102.5%] after:h-[30%] after:left-[-1.5%] after:z-[-1] after:transition-all after:duration-[0.2s] after:ease-in-out after:!mt-0 after:rounded-[5rem] after:bottom-[9%] motion-reduce:after:transition-none after:bg-[rgba(63,120,224,.12)]">{{ t('neler-yapariz.what_we_do.highlight') }}</span> {{ t('neler-yapariz.what_we_do.description_end') }}</p>
<div class="flex flex-wrap mx-[-15px] xl:mx-[-25px] !mt-[-30px]">
<div class="md:w-6/12 lg:w-full xl:w-6/12 w-full flex-[0_0_auto] xl:!px-[25px] !px-[15px] max-w-full !mt-[30px]">
<div class="flex flex-row">
<div>
<div class="icon btn btn-circle btn-lg btn-soft-primary pointer-events-none !mr-5 xl:!text-[1.3rem] w-12 h-12 !text-[calc(1.255rem_+_0.06vw)] inline-flex items-center justify-center leading-none p-0 !rounded-[100%]"> <i class="!text-[calc(1.255rem_+_0.06vw)] before:content-['\ec50'] uil uil-phone-volume"></i> </div>
</div>
<div>
<h4 class="!mb-1">{{ t('neler-yapariz.services.support_24_7.title') }}</h4>
<p class="!mb-0">{{ t('neler-yapariz.services.support_24_7.description') }}</p>
</div>
</div>
</div>
<!--/column -->
<div class="md:w-6/12 lg:w-full xl:w-6/12 w-full flex-[0_0_auto] xl:!px-[25px] !px-[15px] max-w-full !mt-[30px]">
<div class="flex flex-row">
<div>
<div class="icon btn btn-circle btn-lg btn-soft-primary pointer-events-none !mr-5 xl:!text-[1.3rem] w-12 h-12 !text-[calc(1.255rem_+_0.06vw)] inline-flex items-center justify-center leading-none p-0 !rounded-[100%]"> <i class="!text-[calc(1.255rem_+_0.06vw)] before:content-['\ecb3'] uil uil-shield-exclamation"></i> </div>
</div>
<div>
<h4 class="!mb-1">{{ t('neler-yapariz.services.secure_payments.title') }}</h4>
<p class="!mb-0">{{ t('neler-yapariz.services.secure_payments.description') }}</p>
</div>
</div>
</div>
<!--/column -->
<div class="md:w-6/12 lg:w-full xl:w-6/12 w-full flex-[0_0_auto] xl:!px-[25px] !px-[15px] max-w-full !mt-[30px]">
<div class="flex flex-row">
<div>
<div class="icon btn btn-circle btn-lg btn-soft-primary pointer-events-none !mr-5 xl:!text-[1.3rem] w-12 h-12 !text-[calc(1.255rem_+_0.06vw)] inline-flex items-center justify-center leading-none p-0 !rounded-[100%]"> <i class="!text-[calc(1.255rem_+_0.06vw)] before:content-['\ebb2'] uil uil-laptop-cloud"></i> </div>
</div>
<div>
<h4 class="!mb-1">{{ t('neler-yapariz.services.daily_updates.title') }}</h4>
<p class="!mb-0">{{ t('neler-yapariz.services.daily_updates.description') }}</p>
</div>
</div>
</div>
<!--/column -->
<div class="md:w-6/12 lg:w-full xl:w-6/12 w-full flex-[0_0_auto] xl:!px-[25px] !px-[15px] max-w-full !mt-[30px]">
<div class="flex flex-row">
<div>
<div class="icon btn btn-circle btn-lg btn-soft-primary pointer-events-none !mr-5 xl:!text-[1.3rem] w-12 h-12 !text-[calc(1.255rem_+_0.06vw)] inline-flex items-center justify-center leading-none p-0 !rounded-[100%]"> <i class="!text-[calc(1.255rem_+_0.06vw)] before:content-['\e9d3'] uil uil-chart-line"></i> </div>
</div>
<div>
<h4 class="!mb-1">{{ t('neler-yapariz.services.market_research.title') }}</h4>
<p class="!mb-0">{{ t('neler-yapariz.services.market_research.description') }}</p>
</div>
</div>
</div>
<!--/column -->
</div>
<!--/.row -->
</div>
<!--/column -->
</div>
<!--/.row -->
<h2 class="!text-[calc(1.305rem_+_0.66vw)] font-bold xl:!text-[1.8rem] !leading-[1.3] !mb-3">{{ t('neler-yapariz.how_we_do_it.title') }}</h2>
<p class="lead !mb-8 !text-[1.05rem] !leading-[1.6]">{{ t('neler-yapariz.how_we_do_it.description') }} <span class="relative z-[2] whitespace-nowrap after:content-[''] after:block after:absolute after:w-[102.5%] after:h-[30%] after:left-[-1.5%] after:z-[-1] after:transition-all after:duration-[0.2s] after:ease-in-out after:!mt-0 after:rounded-[5rem] after:bottom-[9%] motion-reduce:after:transition-none after:bg-[rgba(63,120,224,.12)]">{{ t('neler-yapariz.how_we_do_it.highlight') }}</span> {{ t('neler-yapariz.how_we_do_it.description_end') }}</p>
<div class="flex flex-wrap mx-[-15px] xl:mx-[-35px] lg:mx-[-20px] !mt-[-30px] process-wrapper line">
<div class="md:w-6/12 lg:w-3/12 xl:w-3/12 w-full flex-[0_0_auto] !px-[15px] xl:!px-[35px] lg:!px-[20px] !mt-[30px] max-w-full !relative after:w-full after:absolute after:content-[''] after:h-px after:z-[1] after:border-t-[rgba(164,174,198,0.2)] after:border-t after:border-solid after:left-[3rem] after:top-6 after:bg-inherit max-lg:after:!hidden"> <span class="icon btn btn-circle btn-lg btn-soft-primary pointer-events-none !mb-4 !relative z-[2] xl:!text-[1.3rem] w-12 h-12 !text-[calc(1.255rem_+_0.06vw)] inline-flex items-center justify-center leading-none !p-0 !rounded-[100%]"><span class="number">01</span></span>
<h4 class="!mb-1">{{ t('neler-yapariz.process.step_1.title') }}</h4>
<p>{{ t('neler-yapariz.process.step_1.description') }}</p>
</div>
<!--/column -->
<div class="md:w-6/12 lg:w-3/12 xl:w-3/12 w-full flex-[0_0_auto] !px-[15px] xl:!px-[35px] lg:!px-[20px] !mt-[30px] max-w-full !relative after:w-full after:absolute after:content-[''] after:h-px after:z-[1] after:border-t-[rgba(164,174,198,0.2)] after:border-t after:border-solid after:left-[3rem] after:top-6 after:bg-inherit max-lg:after:!hidden"> <span class="icon btn btn-circle btn-lg btn-primary !text-white !bg-[#3f78e0] border-[#3f78e0] hover:text-white hover:bg-[#3f78e0] hover:!border-[#3f78e0] active:text-white active:bg-[#3f78e0] active:border-[#3f78e0] disabled:text-white disabled:bg-[#3f78e0] disabled:border-[#3f78e0] pointer-events-none !mb-4 !relative z-[2] xl:!text-[1.3rem] w-12 h-12 !text-[calc(1.255rem_+_0.06vw)] inline-flex items-center justify-center leading-none p-0 !rounded-[100%]"><span class="number">02</span></span>
<h4 class="!mb-1">{{ t('neler-yapariz.process.step_2.title') }}</h4>
<p>{{ t('neler-yapariz.process.step_2.description') }}</p>
</div>
<!--/column -->
<div class="md:w-6/12 lg:w-3/12 xl:w-3/12 w-full flex-[0_0_auto] !px-[15px] xl:!px-[35px] lg:!px-[20px] !mt-[30px] max-w-full !relative after:w-full after:absolute after:content-[''] after:h-px after:z-[1] after:border-t-[rgba(164,174,198,0.2)] after:border-t after:border-solid after:left-[3rem] after:top-6 after:bg-inherit max-lg:after:!hidden"> <span class="icon btn btn-circle btn-lg btn-soft-primary pointer-events-none !mb-4 !relative z-[2] xl:!text-[1.3rem] w-12 h-12 !text-[calc(1.255rem_+_0.06vw)] inline-flex items-center justify-center leading-none !p-0 !rounded-[100%]"><span class="number">03</span></span>
<h4 class="!mb-1">{{ t('neler-yapariz.process.step_3.title') }}</h4>
<p>{{ t('neler-yapariz.process.step_3.description') }}</p>
</div>
<!--/column -->
<div class="md:w-6/12 lg:w-3/12 xl:w-3/12 w-full flex-[0_0_auto] !px-[15px] xl:!px-[35px] lg:!px-[20px] !mt-[30px] max-w-full"> <span class="icon btn btn-circle btn-lg btn-soft-primary pointer-events-none !mb-4 !relative z-[2] xl:!text-[1.3rem] w-12 h-12 !text-[calc(1.255rem_+_0.06vw)] inline-flex items-center justify-center leading-none !p-0 !rounded-[100%]"><span class="number">04</span></span>
<h4 class="!mb-1">{{ t('neler-yapariz.process.step_4.title') }}</h4>
<p>{{ t('neler-yapariz.process.step_4.description') }}</p>
</div>
<!--/column -->
</div>
<!--/.row -->
</div>
<!-- /.container -->
</section>