mirror of
https://github.com/Lapikud/tipilan.git
synced 2026-05-08 18:08:32 +00:00
Added logo animation
This commit is contained in:
@@ -135,3 +135,36 @@ body {
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 1, 'wght' 700, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
|
||||
.tipilan-logo-letter {
|
||||
animation: tipilan-logo-letter-in 720ms cubic-bezier(0.16, 1, 0.3, 1) both;
|
||||
animation-delay: var(--tipilan-logo-letter-delay, 0ms);
|
||||
opacity: 0;
|
||||
transform: translate3d(0, 100%, 0);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
@keyframes tipilan-logo-letter-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, 100%, 0);
|
||||
}
|
||||
|
||||
70% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.tipilan-logo-letter {
|
||||
animation: none;
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
will-change: auto;
|
||||
}
|
||||
}
|
||||
|
||||
84
src/components/AnimatedTipilanLogo.tsx
Normal file
84
src/components/AnimatedTipilanLogo.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import type { AnimationEvent, CSSProperties } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const LOGO_WIDTH = 2092;
|
||||
const LOGO_HEIGHT = 300;
|
||||
|
||||
const logoLetters = [
|
||||
{ letter: "T", src: "/letters/T.svg", x: 0, width: 367 },
|
||||
{ letter: "I", src: "/letters/I.svg", x: 334.858, width: 178 },
|
||||
{ letter: "P", src: "/letters/P.svg", x: 481.258, width: 411 },
|
||||
{ letter: "I", src: "/letters/I.svg", x: 872.218, width: 178 },
|
||||
{ letter: "L", src: "/letters/L.svg", x: 1018.64, width: 286 },
|
||||
{ letter: "A", src: "/letters/A.svg", x: 1289.2, width: 390 },
|
||||
{ letter: "N", src: "/letters/N.svg", x: 1690.72, width: 402 },
|
||||
] as const;
|
||||
|
||||
export default function AnimatedTipilanLogo() {
|
||||
const [isAnimationComplete, setIsAnimationComplete] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
||||
setIsAnimationComplete(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (isAnimationComplete) {
|
||||
return (
|
||||
<Image
|
||||
src="/tipilan-dark.svg"
|
||||
width={LOGO_WIDTH}
|
||||
height={LOGO_HEIGHT}
|
||||
alt="TipiLAN Logo"
|
||||
priority
|
||||
className="relative z-0 w-[max(260px,min(100%,750px))] h-auto"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
aria-label="TipiLAN Logo"
|
||||
className="relative z-0 w-[max(260px,min(100%,750px))] overflow-visible"
|
||||
role="img"
|
||||
style={{ aspectRatio: `${LOGO_WIDTH} / ${LOGO_HEIGHT}` }}
|
||||
>
|
||||
{logoLetters.map((letter, index) => {
|
||||
const isLastLetter = index === logoLetters.length - 1;
|
||||
|
||||
return (
|
||||
<Image
|
||||
key={`${letter.letter}-${letter.x}`}
|
||||
src={letter.src}
|
||||
width={letter.width}
|
||||
height={LOGO_HEIGHT}
|
||||
alt=""
|
||||
aria-hidden
|
||||
priority
|
||||
className="tipilan-logo-letter absolute top-0 h-full object-fill"
|
||||
onAnimationEnd={
|
||||
isLastLetter
|
||||
? (event: AnimationEvent<HTMLImageElement>) => {
|
||||
if (event.animationName === "tipilan-logo-letter-in") {
|
||||
setIsAnimationComplete(true);
|
||||
}
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
style={
|
||||
{
|
||||
left: `${(letter.x / LOGO_WIDTH) * 100}%`,
|
||||
width: `${(letter.width / LOGO_WIDTH) * 100}%`,
|
||||
zIndex: logoLetters.length - index,
|
||||
"--tipilan-logo-letter-delay": `${index * 90}ms`,
|
||||
} as CSSProperties
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import Image from "next/image";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import AnimatedTipilanLogo from "@/components/AnimatedTipilanLogo";
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
@@ -23,14 +24,8 @@ export default function HeroSection() {
|
||||
<div className="relative h-full grid grid-cols-1 md:grid-cols-[3fr_2fr] items-center gap-8 px-8 md:px-12">
|
||||
{/* Left: logo + info + CTA */}
|
||||
<div className="flex flex-col gap-5">
|
||||
<Image
|
||||
src="/tipilan-dark.svg"
|
||||
width={750}
|
||||
height={106}
|
||||
alt="TipiLAN Logo"
|
||||
className="w-[max(260px,min(100%,750px))] h-auto"
|
||||
/>
|
||||
<div className={`${vipnagorgialla.className} font-bold italic`}>
|
||||
<AnimatedTipilanLogo />
|
||||
<div className={`${vipnagorgialla.className} relative z-10 font-bold italic`}>
|
||||
<p className="text-[clamp(1.1rem,0.9rem+1vw,1.75rem)] text-[#00A3E0] uppercase tracking-wide">
|
||||
{t("hero.date")}
|
||||
</p>
|
||||
@@ -40,7 +35,7 @@ export default function HeroSection() {
|
||||
</div>
|
||||
<Link
|
||||
href="/piletid"
|
||||
className={`self-start px-6 py-3 bg-[#007CAB] hover:bg-[#00A3E0] text-[#EEE5E5] ${vipnagorgialla.className} font-bold italic text-[clamp(1rem,0.8rem+0.8vw,1.5rem)] uppercase transition`}
|
||||
className={`relative z-10 self-start px-6 py-3 bg-[#007CAB] hover:bg-[#00A3E0] text-[#EEE5E5] ${vipnagorgialla.className} font-bold italic text-[clamp(1rem,0.8rem+0.8vw,1.5rem)] uppercase transition`}
|
||||
>
|
||||
{t("hero.buyTicket")}
|
||||
</Link>
|
||||
|
||||
Reference in New Issue
Block a user