add sponsor logo, enable hover scroll on sponsors container

This commit is contained in:
Katri Lotamõis
2026-09-04 13:52:37 +03:00
parent 3eb7202237
commit 70f9e54ce4
4 changed files with 166 additions and 57 deletions

11
package-lock.json generated
View File

@@ -9262,17 +9262,6 @@
} }
} }
}, },
"node_modules/next-intl/node_modules/@swc/helpers": {
"version": "0.5.23",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz",
"integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==",
"license": "Apache-2.0",
"optional": true,
"peer": true,
"dependencies": {
"tslib": "^2.8.0"
}
},
"node_modules/next-themes": { "node_modules/next-themes": {
"version": "0.4.6", "version": "0.4.6",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",

BIN
public/sponsors/istar.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -0,0 +1,100 @@
"use client";
import { useRef, useEffect, ReactNode } from "react";
interface HoverTickerProps {
children: ReactNode;
className?: string;
baseSpeed?: number;
hoverSpeed?: number;
}
export default function HoverTicker({
children,
className = "",
baseSpeed = 1.2,
hoverSpeed = 3.5,
}: HoverTickerProps) {
const containerRef = useRef<HTMLDivElement>(null);
const mouseZoneRef = useRef<"left" | "right" | "paused" | "none">("none");
useEffect(() => {
const container = containerRef.current;
if (!container) return;
let animationFrameId: number;
const animate = () => {
if (container) {
const zone = mouseZoneRef.current;
if (zone === "none") {
container.scrollLeft += baseSpeed;
} else if (zone === "right") {
container.scrollLeft += hoverSpeed;
} else if (zone === "left") {
container.scrollLeft -= hoverSpeed;
}
// Infinite scroll cycle
const maxScroll = container.scrollWidth / 2;
if (container.scrollLeft >= maxScroll) {
container.scrollLeft -= maxScroll / 2;
} else if (container.scrollLeft <= 0 && (zone === "left" || zone === "paused")) {
container.scrollLeft += maxScroll / 2;
}
}
animationFrameId = requestAnimationFrame(animate);
};
animationFrameId = requestAnimationFrame(animate);
return () => cancelAnimationFrame(animationFrameId);
}, [baseSpeed, hoverSpeed]);
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
const container = containerRef.current;
if (!container) return;
const rect = container.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const width = rect.width;
if (mouseX < width * 0.3) {
mouseZoneRef.current = "left";
} else if (mouseX > width * 0.7) {
mouseZoneRef.current = "right";
} else {
mouseZoneRef.current = "paused";
}
};
const handleMouseLeave = () => {
mouseZoneRef.current = "none";
};
return (
<div
ref={containerRef}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
className={`ticker-container relative overflow-x-auto select-none ${className}`}
>
<div className="flex items-center w-max">
{children}
</div>
<style jsx>{`
.ticker-container {
-ms-overflow-style: none;
scrollbar-width: none;
}
.ticker-container::-webkit-scrollbar {
display: none;
}
`}</style>
</div>
);
}

View File

@@ -4,6 +4,7 @@ import { vipnagorgialla } from "@/components/Vipnagorgialla";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import Image from "next/image"; import Image from "next/image";
import NextLink from "next/link"; import NextLink from "next/link";
import HoverTicker from "@/components/HoverTicker";
interface Sponsor { interface Sponsor {
href: string; href: string;
@@ -157,6 +158,13 @@ const sponsors: Sponsor[] = [
width: 244, width: 244,
height: 244, height: 244,
}, },
{
href: "",
src: "/sponsors/istar.jpg",
alt: "iStar Kebab",
width: 244,
height: 244
},
]; ];
interface SponsorsProps { interface SponsorsProps {
@@ -182,8 +190,8 @@ export default function Sponsors({
</h3> </h3>
)} )}
<div className="relative xl:flex-1 overflow-hidden py-8 sm:py-10 xl:py-4 2xl:py-6"> <HoverTicker className="xl:flex-1 py-8 sm:py-10 xl:py-4 2xl:py-6">
<div className="ticker-track flex items-center w-max gap-8 sm:gap-10 md:gap-12 xl:gap-16 2xl:gap-20 px-8 sm:px-10 xl:px-14 2xl:px-20"> <div className="flex items-center gap-8 sm:gap-10 md:gap-12 xl:gap-16 2xl:gap-20 px-8 sm:px-10 xl:px-14 2xl:px-20">
{tickerSponsors.map((sponsor, index) => ( {tickerSponsors.map((sponsor, index) => (
<NextLink <NextLink
key={`${sponsor.alt}-${index}`} key={`${sponsor.alt}-${index}`}
@@ -203,14 +211,26 @@ export default function Sponsors({
</NextLink> </NextLink>
))} ))}
</div> </div>
</div> </HoverTicker>
<style jsx>{` <style jsx>{`
.ticker-container {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.ticker-container::-webkit-scrollbar {
display: none; /* Chrome, Safari, Opera */
}
.ticker-track { .ticker-track {
animation: sponsors-ticker 36s linear infinite; animation: sponsors-ticker 36s linear infinite;
will-change: transform; will-change: transform;
} }
.ticker-container:hover .ticker-track {
animation-play-state: paused;
}
@keyframes sponsors-ticker { @keyframes sponsors-ticker {
from { from {
transform: translateX(0%); transform: translateX(0%);