mirror of
https://github.com/Lapikud/tipilan.git
synced 2026-09-22 07:17:41 +00:00
add sponsor logo, enable hover scroll on sponsors container
This commit is contained in:
11
package-lock.json
generated
11
package-lock.json
generated
@@ -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": {
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
|
||||
|
||||
BIN
public/sponsors/istar.jpg
Normal file
BIN
public/sponsors/istar.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
100
src/components/HoverTicker.tsx
Normal file
100
src/components/HoverTicker.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
import NextLink from "next/link";
|
||||
import HoverTicker from "@/components/HoverTicker";
|
||||
|
||||
interface Sponsor {
|
||||
href: string;
|
||||
@@ -157,6 +158,13 @@ const sponsors: Sponsor[] = [
|
||||
width: 244,
|
||||
height: 244,
|
||||
},
|
||||
{
|
||||
href: "",
|
||||
src: "/sponsors/istar.jpg",
|
||||
alt: "iStar Kebab",
|
||||
width: 244,
|
||||
height: 244
|
||||
},
|
||||
];
|
||||
|
||||
interface SponsorsProps {
|
||||
@@ -182,8 +190,8 @@ export default function Sponsors({
|
||||
</h3>
|
||||
)}
|
||||
|
||||
<div className="relative xl:flex-1 overflow-hidden 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">
|
||||
<HoverTicker className="xl:flex-1 py-8 sm:py-10 xl:py-4 2xl:py-6">
|
||||
<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) => (
|
||||
<NextLink
|
||||
key={`${sponsor.alt}-${index}`}
|
||||
@@ -203,14 +211,26 @@ export default function Sponsors({
|
||||
</NextLink>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</HoverTicker>
|
||||
|
||||
<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 {
|
||||
animation: sponsors-ticker 36s linear infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.ticker-container:hover .ticker-track {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
|
||||
@keyframes sponsors-ticker {
|
||||
from {
|
||||
transform: translateX(0%);
|
||||
|
||||
Reference in New Issue
Block a user