mirror of
https://github.com/Lapikud/tipilan.git
synced 2026-05-08 18:08:32 +00:00
Carusel changes to previous ver, sponsors L to R
This commit is contained in:
@@ -74,6 +74,10 @@ const Header = ({ navItems }: HeaderProps) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsMobileMenuOpen(false);
|
||||||
|
}, [pathname]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="px-4 py-2 md:px-8 flex items-center bg-[#0E0F19] border-b-3 border-[#1F5673] justify-between">
|
<header className="px-4 py-2 md:px-8 flex items-center bg-[#0E0F19] border-b-3 border-[#1F5673] justify-between">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
@@ -90,7 +94,7 @@ const Header = ({ navItems }: HeaderProps) => {
|
|||||||
{/* Right side - Navigation + controls */}
|
{/* Right side - Navigation + controls */}
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{/* Desktop Navigation */}
|
{/* Desktop Navigation */}
|
||||||
<nav className="hidden xl:flex items-center gap-3">
|
<nav className="hidden lg:flex items-center gap-3">
|
||||||
{mainNavItems.map((item) => {
|
{mainNavItems.map((item) => {
|
||||||
const isActive = pathname === item.href;
|
const isActive = pathname === item.href;
|
||||||
const isDisabled = disabledNavHrefs.has(item.href);
|
const isDisabled = disabledNavHrefs.has(item.href);
|
||||||
@@ -110,20 +114,7 @@ const Header = ({ navItems }: HeaderProps) => {
|
|||||||
: "hover:bg-[#00A3E0]/20"
|
: "hover:bg-[#00A3E0]/20"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span className="flex items-center gap-2">
|
{item.label}
|
||||||
<span>{item.label}</span>
|
|
||||||
{navIconByHref[item.href] ? (
|
|
||||||
<span
|
|
||||||
className={`material-symbols-outlined text-[1.4rem]! leading-none ${
|
|
||||||
isActive
|
|
||||||
? "text-black"
|
|
||||||
: "text-[#00A3E0] group-hover:text-[#EEE5E5]"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{navIconByHref[item.href]}
|
|
||||||
</span>
|
|
||||||
) : null}
|
|
||||||
</span>
|
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -139,7 +130,7 @@ const Header = ({ navItems }: HeaderProps) => {
|
|||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="xl:hidden size-10 cursor-pointer"
|
className="lg:hidden size-10 cursor-pointer"
|
||||||
>
|
>
|
||||||
<MdMenu className="size-10 text-[#EEE5E5]" />
|
<MdMenu className="size-10 text-[#EEE5E5]" />
|
||||||
<span className="sr-only">Menu</span>
|
<span className="sr-only">Menu</span>
|
||||||
@@ -147,7 +138,7 @@ const Header = ({ navItems }: HeaderProps) => {
|
|||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent
|
<DropdownMenuContent
|
||||||
align="end"
|
align="end"
|
||||||
className="xl:hidden w-64 translate-y-4 rounded-none border-3 border-[#1F5673] bg-[#0E0F19] p-0"
|
className="lg:hidden w-64 translate-y-4 rounded-none border-3 border-[#1F5673] bg-[#0E0F19] p-0"
|
||||||
>
|
>
|
||||||
{mainNavItems.map((item, index) => {
|
{mainNavItems.map((item, index) => {
|
||||||
const isActive = pathname === item.href;
|
const isActive = pathname === item.href;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from "react";
|
|
||||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
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";
|
||||||
@@ -83,38 +82,22 @@ const sponsors: Sponsor[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Split sponsors into slides (6 per slide)
|
|
||||||
const SPONSORS_PER_SLIDE = 6;
|
|
||||||
const slides: Sponsor[][] = [];
|
|
||||||
for (let i = 0; i < sponsors.length; i += SPONSORS_PER_SLIDE) {
|
|
||||||
slides.push(sponsors.slice(i, i + SPONSORS_PER_SLIDE));
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SponsorsProps {
|
interface SponsorsProps {
|
||||||
showTitle?: boolean;
|
showTitle?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tickerSponsors = [...sponsors, ...sponsors, ...sponsors, ...sponsors];
|
||||||
|
|
||||||
export default function Sponsors({
|
export default function Sponsors({
|
||||||
showTitle = true,
|
showTitle = true,
|
||||||
className = "",
|
className = "",
|
||||||
}: SponsorsProps) {
|
}: SponsorsProps) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const [current, setCurrent] = useState(0);
|
|
||||||
|
|
||||||
const next = useCallback(
|
|
||||||
() => setCurrent((c) => (c + 1) % slides.length),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const id = setInterval(next, 5000);
|
|
||||||
return () => clearInterval(id);
|
|
||||||
}, [next]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`flex flex-col max-w-[1920px] xl:h-[414px] mx-auto ${vipnagorgialla.className} font-bold italic border-[#1F5673] ${className}`}
|
className={`flex flex-col w-full xl:h-[414px] mx-auto ${vipnagorgialla.className} font-bold italic border-[#1F5673] ${className}`}
|
||||||
>
|
>
|
||||||
{showTitle && (
|
{showTitle && (
|
||||||
<h3 className="text-4xl md:text-5xl dark:text-[#EEE5E5] text-[#2A2C3F] px-12 pt-8 pb-4">
|
<h3 className="text-4xl md:text-5xl dark:text-[#EEE5E5] text-[#2A2C3F] px-12 pt-8 pb-4">
|
||||||
@@ -122,53 +105,44 @@ export default function Sponsors({
|
|||||||
</h3>
|
</h3>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Carousel container */}
|
<div className="relative xl:flex-1 overflow-hidden py-8 sm:py-10 xl:py-4 2xl:py-6">
|
||||||
<div className="relative xl:flex-1 overflow-x-hidden overflow-y-visible">
|
<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
|
{tickerSponsors.map((sponsor, index) => (
|
||||||
className="flex h-full transition-transform duration-500 ease-in-out"
|
<NextLink
|
||||||
style={{ transform: `translateX(-${current * 100}%)` }}
|
key={`${sponsor.alt}-${index}`}
|
||||||
>
|
href={sponsor.href}
|
||||||
{slides.map((slideSponsors, slideIndex) => (
|
target="_blank"
|
||||||
<div
|
className="flex items-center justify-center shrink-0"
|
||||||
key={slideIndex}
|
aria-hidden={index >= sponsors.length}
|
||||||
className="flex-none w-full xl:h-full grid grid-cols-2 sm:grid-cols-3 place-items-center gap-6 px-6 py-6 xl:flex xl:items-center xl:justify-center xl:gap-12 xl:px-12 xl:py-0"
|
tabIndex={index >= sponsors.length ? -1 : undefined}
|
||||||
>
|
>
|
||||||
{slideSponsors.map((sponsor, i) => (
|
<Image
|
||||||
<NextLink
|
src={sponsor.src}
|
||||||
key={i}
|
alt={sponsor.alt}
|
||||||
href={sponsor.href}
|
width={sponsor.width}
|
||||||
target="_blank"
|
height={sponsor.height}
|
||||||
className="flex items-center justify-center w-full"
|
className={`object-contain max-h-[80px] max-w-[120px] sm:max-h-[110px] sm:max-w-[150px] md:max-h-[130px] md:max-w-[180px] lg:max-h-[140px] lg:max-w-[200px] xl:max-h-[180px] xl:max-w-[240px] 2xl:max-h-[210px] 2xl:max-w-[280px] ${sponsor.className || ""}`}
|
||||||
>
|
/>
|
||||||
<Image
|
</NextLink>
|
||||||
src={sponsor.src}
|
|
||||||
alt={sponsor.alt}
|
|
||||||
width={sponsor.width}
|
|
||||||
height={sponsor.height}
|
|
||||||
className={`object-contain max-h-[80px] max-w-[120px] sm:max-h-[110px] sm:max-w-[150px] md:max-h-[130px] md:max-w-[180px] lg:max-h-[140px] lg:max-w-[200px] xl:max-h-[180px] xl:max-w-[240px] ${sponsor.className || ""}`}
|
|
||||||
/>
|
|
||||||
</NextLink>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Navigation dots */}
|
<style jsx>{`
|
||||||
<div className="flex justify-center gap-3 py-4">
|
.ticker-track {
|
||||||
{slides.map((_, i) => (
|
animation: sponsors-ticker 36s linear infinite;
|
||||||
<button
|
will-change: transform;
|
||||||
key={i}
|
}
|
||||||
onClick={() => setCurrent(i)}
|
|
||||||
className={`w-3 h-3 rounded-full transition ${
|
@keyframes sponsors-ticker {
|
||||||
i === current
|
from {
|
||||||
? "bg-[#00A3E0]"
|
transform: translateX(-25%);
|
||||||
: "bg-[#1F5673] hover:bg-[#007CAB]/60"
|
}
|
||||||
}`}
|
to {
|
||||||
aria-label={`Slide ${i + 1}`}
|
transform: translateX(0%);
|
||||||
/>
|
}
|
||||||
))}
|
}
|
||||||
</div>
|
`}</style>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect, useCallback, useRef } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||||
@@ -64,6 +64,7 @@ const slides: Slide[] = [
|
|||||||
export default function TeaserCarousel() {
|
export default function TeaserCarousel() {
|
||||||
const t = useTranslations("home.teaser");
|
const t = useTranslations("home.teaser");
|
||||||
const [current, setCurrent] = useState(0);
|
const [current, setCurrent] = useState(0);
|
||||||
|
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||||
|
|
||||||
const next = useCallback(
|
const next = useCallback(
|
||||||
() => setCurrent((c) => (c + 1) % slides.length),
|
() => setCurrent((c) => (c + 1) % slides.length),
|
||||||
@@ -71,66 +72,91 @@ export default function TeaserCarousel() {
|
|||||||
);
|
);
|
||||||
const prev = () => setCurrent((c) => (c - 1 + slides.length) % slides.length);
|
const prev = () => setCurrent((c) => (c - 1 + slides.length) % slides.length);
|
||||||
|
|
||||||
useEffect(() => {
|
const restartAutoplay = useCallback(() => {
|
||||||
const id = setInterval(next, 5000);
|
if (intervalRef.current) {
|
||||||
return () => clearInterval(id);
|
clearInterval(intervalRef.current);
|
||||||
|
}
|
||||||
|
intervalRef.current = setInterval(next, 5000);
|
||||||
}, [next]);
|
}, [next]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
restartAutoplay();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (intervalRef.current) {
|
||||||
|
clearInterval(intervalRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [restartAutoplay]);
|
||||||
|
|
||||||
|
const headingOnRight = Boolean(slides[current]?.flip);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-b-3 border-[#1F5673]">
|
<div className="border-b-3 border-[#1F5673]">
|
||||||
{/* Sliding track */}
|
{/* Slides (fade transition + hero lift effect) */}
|
||||||
<div className="relative h-[729px] overflow-hidden">
|
<div className="relative h-[729px] overflow-hidden">
|
||||||
<div
|
{slides.map((slide, i) => {
|
||||||
className="flex h-full transition-transform duration-500 ease-in-out"
|
const title = t(`${slide.key}.title`);
|
||||||
style={{ transform: `translateX(-${current * 100}%)` }}
|
const description = t(`${slide.key}.description`);
|
||||||
>
|
const isActive = i === current;
|
||||||
{slides.map((slide) => {
|
|
||||||
const title = t(`${slide.key}.title`);
|
|
||||||
const description = t(`${slide.key}.description`);
|
|
||||||
return (
|
|
||||||
<div key={slide.key} className="relative flex-none w-full h-full">
|
|
||||||
{/* Background image */}
|
|
||||||
<Image
|
|
||||||
src={slide.image}
|
|
||||||
alt={slide.imageAlt}
|
|
||||||
fill
|
|
||||||
className="object-cover object-center"
|
|
||||||
/>
|
|
||||||
{/* Overlay */}
|
|
||||||
<div
|
|
||||||
className={`absolute inset-0 ${slide.fullBrightness ? "" : "bg-gradient-to-r from-[#0E0F19]/90 via-[#0E0F19]/60 to-[#0E0F19]/20"}`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Content */}
|
return (
|
||||||
|
<div
|
||||||
|
key={slide.key}
|
||||||
|
className={`absolute inset-0 transition-opacity duration-700 ease-out ${
|
||||||
|
isActive ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{/* Background image */}
|
||||||
|
<Image
|
||||||
|
src={slide.image}
|
||||||
|
alt={slide.imageAlt}
|
||||||
|
fill
|
||||||
|
className="object-cover object-center"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Overlay */}
|
||||||
|
<div
|
||||||
|
className={`absolute inset-0 ${slide.fullBrightness ? "" : "bg-gradient-to-r from-[#0E0F19]/90 via-[#0E0F19]/60 to-[#0E0F19]/20"}`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div
|
||||||
|
className={`relative grid grid-cols-1 md:grid-cols-2 h-full ${slide.flip ? "md:[direction:rtl]" : ""}`}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className={`relative grid grid-cols-1 md:grid-cols-2 h-full ${slide.flip ? "md:[direction:rtl]" : ""}`}
|
className={`flex flex-col justify-end px-8 py-8 md:px-12 md:py-10 ${slide.flip ? "md:[direction:ltr]" : ""}`}
|
||||||
|
>
|
||||||
|
{/* Title + description at bottom */}
|
||||||
|
<div
|
||||||
|
className={`flex flex-col gap-3 pb-16 ${slide.flip ? "md:items-end md:text-right md:ml-auto" : ""}`}
|
||||||
|
>
|
||||||
|
<Link href={slide.href}>
|
||||||
|
<h3
|
||||||
|
className={`${vipnagorgialla.className} font-bold italic text-[clamp(2.5rem,2rem+2.5vw,5rem)] leading-none text-[#EEE5E5] hover:text-[#00A3E0] transition`}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
</Link>
|
||||||
|
<p
|
||||||
|
className={`text-[1.1rem] leading-relaxed md:text-[clamp(0.875rem,0.75rem+0.5vw,1.1rem)] text-[#EEE5E5] max-w-prose ${slide.flip ? "md:text-right" : ""}`}
|
||||||
|
>
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Hero image */}
|
||||||
|
<div
|
||||||
|
className={`hidden md:block relative overflow-hidden ${slide.flip ? "md:[direction:ltr]" : ""}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`flex flex-col justify-between px-8 py-8 md:px-12 md:py-10 ${slide.flip ? "md:[direction:ltr]" : ""}`}
|
className="absolute inset-0 transition-transform duration-700 ease-out"
|
||||||
>
|
style={{
|
||||||
{/* Heading at top */}
|
transform: isActive
|
||||||
<h2
|
? "translateY(0)"
|
||||||
className={`${vipnagorgialla.className} font-bold italic text-[clamp(2.5rem,1.5rem+4.5vw,4rem)] md:text-[64px] leading-none tracking-normal uppercase text-[#EEE5E5]`}
|
: "translateY(110%)",
|
||||||
>
|
}}
|
||||||
{highlightLAN(t("heading"))}
|
|
||||||
</h2>
|
|
||||||
{/* Title + description at bottom */}
|
|
||||||
<div className="flex flex-col gap-3 pb-16">
|
|
||||||
<Link href={slide.href}>
|
|
||||||
<h3
|
|
||||||
className={`${vipnagorgialla.className} font-bold italic text-[clamp(2.5rem,2rem+2.5vw,5rem)] leading-none text-[#EEE5E5] hover:text-[#00A3E0] transition`}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</h3>
|
|
||||||
</Link>
|
|
||||||
<p className="text-[clamp(0.875rem,0.75rem+0.5vw,1.1rem)] text-[#EEE5E5] max-w-prose">
|
|
||||||
{description}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* Hero image */}
|
|
||||||
<div
|
|
||||||
className={`hidden md:block relative ${slide.flip ? "md:[direction:ltr]" : ""}`}
|
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src={slide.hero}
|
src={slide.hero}
|
||||||
@@ -141,20 +167,52 @@ export default function TeaserCarousel() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
})}
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
{/* Floating heading (mobile) */}
|
||||||
|
<div className="absolute top-5 inset-x-0 px-8 z-20 md:hidden pointer-events-none">
|
||||||
|
<h2
|
||||||
|
className={`${vipnagorgialla.className} font-bold italic text-[clamp(2rem,1.5rem+4.6vw,3rem)] leading-[0.95] tracking-normal uppercase text-[#EEE5E5] whitespace-normal break-words text-left max-w-[12ch]`}
|
||||||
|
>
|
||||||
|
{highlightLAN(t("heading"))}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Floating heading (desktop/tablet) */}
|
||||||
|
<div className="absolute top-8 inset-x-0 px-4 sm:px-6 md:px-12 z-20 hidden md:flex pointer-events-none">
|
||||||
|
<div
|
||||||
|
className="transition-[flex-grow] duration-700 ease-out"
|
||||||
|
style={{ flexGrow: headingOnRight ? 1 : 0 }}
|
||||||
|
/>
|
||||||
|
<h2
|
||||||
|
className={`${vipnagorgialla.className} font-bold italic text-[64px] leading-none tracking-normal uppercase text-[#EEE5E5] whitespace-normal [overflow-wrap:anywhere] text-center shrink`}
|
||||||
|
>
|
||||||
|
{highlightLAN(t("heading"))}
|
||||||
|
</h2>
|
||||||
|
<div
|
||||||
|
className="transition-[flex-grow] duration-700 ease-out"
|
||||||
|
style={{ flexGrow: headingOnRight ? 0 : 1 }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Arrow buttons */}
|
{/* Arrow buttons */}
|
||||||
<button
|
<button
|
||||||
onClick={prev}
|
onClick={() => {
|
||||||
|
prev();
|
||||||
|
restartAutoplay();
|
||||||
|
}}
|
||||||
className="absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center bg-[#0E0F19]/50 hover:bg-[#007CAB] text-[#EEE5E5] transition z-20"
|
className="absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center bg-[#0E0F19]/50 hover:bg-[#007CAB] text-[#EEE5E5] transition z-20"
|
||||||
aria-label="Previous slide"
|
aria-label="Previous slide"
|
||||||
>
|
>
|
||||||
<span className="material-symbols-outlined">chevron_left</span>
|
<span className="material-symbols-outlined">chevron_left</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={next}
|
onClick={() => {
|
||||||
|
next();
|
||||||
|
restartAutoplay();
|
||||||
|
}}
|
||||||
className="absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center bg-[#0E0F19]/50 hover:bg-[#007CAB] text-[#EEE5E5] transition z-20"
|
className="absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center bg-[#0E0F19]/50 hover:bg-[#007CAB] text-[#EEE5E5] transition z-20"
|
||||||
aria-label="Next slide"
|
aria-label="Next slide"
|
||||||
>
|
>
|
||||||
@@ -166,7 +224,10 @@ export default function TeaserCarousel() {
|
|||||||
{slides.map((_, i) => (
|
{slides.map((_, i) => (
|
||||||
<button
|
<button
|
||||||
key={i}
|
key={i}
|
||||||
onClick={() => setCurrent(i)}
|
onClick={() => {
|
||||||
|
setCurrent(i);
|
||||||
|
restartAutoplay();
|
||||||
|
}}
|
||||||
className={`w-3 h-3 rounded-full transition ${
|
className={`w-3 h-3 rounded-full transition ${
|
||||||
i === current
|
i === current
|
||||||
? "bg-[#00A3E0]"
|
? "bg-[#00A3E0]"
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ export default function middleware(request: NextRequest) {
|
|||||||
if (location) {
|
if (location) {
|
||||||
const url = new URL(location);
|
const url = new URL(location);
|
||||||
|
|
||||||
// Keep localhost development redirects intact, but drop leaked :3000
|
// Keep localhost development redirects intact. If not then DO NOT!
|
||||||
// on public domains when upstream proxy forwards an internal port.
|
|
||||||
const isLocalhost =
|
const isLocalhost =
|
||||||
url.hostname === "localhost" || url.hostname === "127.0.0.1";
|
url.hostname === "localhost" || url.hostname === "127.0.0.1";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user