mirror of
https://github.com/PeterMaquiran/tvone.git
synced 2026-04-18 07:17:52 +00:00
+103
-43
@@ -1,76 +1,136 @@
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
const slides = [
|
||||
{
|
||||
id: 1,
|
||||
tag: "MÚSICA",
|
||||
title:
|
||||
"Diddy na XB Label? Gerilson Israel responde após anúncio de lançamento de nova música em conjunto.",
|
||||
title: "Diddy na XB Label? Gerilson Israel responde após anúncio de lançamento de nova música em conjunto.",
|
||||
byline: "Por Redação — 24 de Março, 2025",
|
||||
image:
|
||||
"https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?w=1400&q=80",
|
||||
image: "https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?w=1400&q=80",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
tag: "CULTURA",
|
||||
title: "Festivais de verão: calendário completo e bilhetes à venda esta semana.",
|
||||
byline: "Por Equipa tvone — 23 de Março, 2025",
|
||||
image:
|
||||
"https://images.unsplash.com/photo-1459749411175-04bf5292ceea?w=1400&q=80",
|
||||
image: "https://images.unsplash.com/photo-1459749411175-04bf5292ceea?w=1400&q=80",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
tag: "TV",
|
||||
title: "Novas séries internacionais chegam às plataformas — o que não pode perder.",
|
||||
byline: "Por Redação — 22 de Março, 2025",
|
||||
image:
|
||||
"https://images.unsplash.com/photo-1522869635100-9f4c5e86aa37?w=1400&q=80",
|
||||
image: "https://images.unsplash.com/photo-1522869635100-9f4c5e86aa37?w=1400&q=80",
|
||||
},
|
||||
];
|
||||
|
||||
export function TvoneHero() {
|
||||
const [active, setActive] = useState(0);
|
||||
const slide = slides[active]!;
|
||||
const [isPaused, setIsPaused] = useState(false);
|
||||
|
||||
// --- AUTO-PLAY LOGIC ---
|
||||
useEffect(() => {
|
||||
if (isPaused) return;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
setActive((prev) => (prev + 1) % slides.length);
|
||||
}, 3000); // 3 Seconds
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [isPaused, active]);
|
||||
|
||||
return (
|
||||
<section className="mx-auto w-full max-w-[1200px] px-4 py-6 pb-20 pt-12">
|
||||
<div className="relative overflow-hidden shadow-[0_12px_40px_rgba(0,0,0,0.12)] rounded-[24px] ">
|
||||
<div className="relative aspect-[21/9] min-h-[280px] w-full md:aspect-[2.4/1] rounded-xl">
|
||||
<Image
|
||||
src={slide.image}
|
||||
alt=""
|
||||
fill
|
||||
className="object-cover rounded-xl"
|
||||
sizes="(max-width: 1200px) 100vw, 1200px"
|
||||
priority
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/75 via-black/25 to-transparent" />
|
||||
<div className="absolute inset-0 flex flex-col justify-end p-6 md:p-10">
|
||||
<span className="mb-2 inline-flex w-fit px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide bg-blue-600 text-white">
|
||||
{slide.tag}
|
||||
</span>
|
||||
<h1 className="max-w-3xl text-balance text-2xl font-bold leading-tight text-white md:text-3xl lg:text-4xl">
|
||||
{slide.title}
|
||||
</h1>
|
||||
<p className="mt-3 text-sm text-white/85">{slide.byline}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute bottom-4 left-0 right-0 z-10 flex justify-center gap-2 md:bottom-6">
|
||||
{slides.map((s, i) => (
|
||||
<button
|
||||
key={s.id}
|
||||
type="button"
|
||||
onClick={() => setActive(i)}
|
||||
className={`h-2 w-2 rounded-full transition ${i === active ? "bg-white" : "bg-white/45 hover:bg-white/70"}`}
|
||||
aria-label={`Slide ${i + 1}`}
|
||||
aria-current={i === active}
|
||||
<section
|
||||
className="relative isolate w-full min-h-[600px] flex items-center justify-center px-4 py-20 mb-10 overflow-hidden"
|
||||
onMouseEnter={() => setIsPaused(true)}
|
||||
onMouseLeave={() => setIsPaused(false)}
|
||||
>
|
||||
|
||||
{/* --- SMOOTH BACKGROUND CROSSFADE --- */}
|
||||
<div className="absolute inset-0 -z-10 bg-black">
|
||||
{slides.map((s, i) => (
|
||||
<div
|
||||
key={s.id}
|
||||
className={`absolute inset-0 transition-all duration-[1500ms] ease-in-out ${
|
||||
i === active ? "opacity-90 scale-110 rotate-0" : "opacity-0 scale-125 rotate-2"
|
||||
}`}
|
||||
>
|
||||
<Image
|
||||
src={s.image}
|
||||
alt=""
|
||||
fill
|
||||
className="object-cover blur-[100px] saturate-[2]"
|
||||
priority={i === 0}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
<div className="absolute inset-0 bg-black/30" />
|
||||
</div>
|
||||
|
||||
<div className="relative w-full max-w-[1100px] z-10">
|
||||
<div className="relative overflow-hidden shadow-[0_50px_100px_rgba(0,0,0,0.6)] rounded-[40px] bg-black border border-white/10 transition-transform duration-500 hover:scale-[1.01]">
|
||||
|
||||
<div className="relative aspect-[21/9] min-h-[400px] w-full md:aspect-[2.4/1] overflow-hidden">
|
||||
{/* Main Image Crossfade */}
|
||||
{slides.map((s, i) => (
|
||||
<Image
|
||||
key={s.id}
|
||||
src={s.image}
|
||||
alt={s.title}
|
||||
fill
|
||||
className={`object-cover transition-all duration-[1200ms] ease-in-out ${
|
||||
i === active ? "opacity-100 scale-100" : "opacity-0 scale-105"
|
||||
}`}
|
||||
sizes="(max-width: 1200px) 100vw, 1200px"
|
||||
priority={i === active}
|
||||
/>
|
||||
))}
|
||||
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/95 via-black/20 to-transparent" />
|
||||
|
||||
{/* Text Content */}
|
||||
<div className="absolute inset-0 flex flex-col justify-end p-8 md:p-16">
|
||||
<div className="overflow-hidden">
|
||||
<span className="inline-flex px-3 py-1 text-[11px] font-black uppercase tracking-[0.2em] bg-blue-600 text-white rounded-md mb-4 shadow-lg">
|
||||
{slides[active].tag}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h1 className="max-w-4xl text-balance text-3xl font-extrabold leading-[1.1] text-white md:text-5xl tracking-tighter">
|
||||
{slides[active].title}
|
||||
</h1>
|
||||
|
||||
<p className="mt-6 text-sm font-medium text-white/50 flex items-center gap-3">
|
||||
<span className="h-[1px] w-8 bg-blue-600" />
|
||||
{slides[active].byline}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* iOS Floating Control Bar */}
|
||||
<div className="absolute bottom-8 left-0 right-0 z-20 flex justify-center">
|
||||
<nav className="flex items-center gap-3 px-5 py-3 rounded-2xl bg-black/20 backdrop-blur-2xl border border-white/10 shadow-2xl">
|
||||
{slides.map((s, i) => (
|
||||
<button
|
||||
key={s.id}
|
||||
onClick={() => setActive(i)}
|
||||
className="relative group py-2"
|
||||
aria-label={`Go to slide ${i + 1}`}
|
||||
>
|
||||
<div className={`relative h-1.5 rounded-full transition-all duration-500 ease-out ${
|
||||
i === active
|
||||
? "w-12 bg-white shadow-[0_0_20px_rgba(255,255,255,0.8)]"
|
||||
: "w-2 bg-white/20 group-hover:bg-white/40"
|
||||
}`} />
|
||||
</button>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user