add category
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-04-15 09:58:11 +01:00
parent f110435720
commit c46857514b
5 changed files with 561 additions and 44 deletions
+22 -39
View File
@@ -4,7 +4,6 @@ import Image from "next/image";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import type { CSSProperties } from "react";
// Definição do tipo para garantir 100% de compatibilidade TS
export interface SliderPhoto {
src: string;
alt: string;
@@ -13,13 +12,12 @@ export interface SliderPhoto {
const ROTATE_MS = 5500;
// --- 1. COMPONENTE DE SLIDE INDIVIDUAL ---
// --- 1. SLIDE COMPONENT ---
interface SlideProps {
photo: SliderPhoto;
onRatioLoad: (src: string, ratio: number) => void;
}
function PromoStripSingleSlide({ photo, onRatioLoad }: SlideProps) {
function PromoStripSingleSlide({ photo }: SlideProps) {
return (
<div className="relative h-full w-full">
<Image
@@ -29,19 +27,12 @@ function PromoStripSingleSlide({ photo, onRatioLoad }: SlideProps) {
priority
className="object-cover object-center"
sizes="100vw"
onLoad={(e) => {
const target = e.currentTarget;
if (target.naturalHeight > 0) {
onRatioLoad(photo.src, target.naturalWidth / target.naturalHeight);
}
}}
/>
</div>
);
}
// --- 2. HOOK DE DADOS (Simulação de Fetch) ---
// --- 2. DATA HOOK ---
function useSliderPhotos(): { photos: SliderPhoto[]; loading: boolean } {
const [photos, setPhotos] = useState<SliderPhoto[]>([]);
const [loading, setLoading] = useState<boolean>(true);
@@ -72,14 +63,15 @@ function useSliderPhotos(): { photos: SliderPhoto[]; loading: boolean } {
return { photos, loading };
}
// --- 3. COMPONENTE PRINCIPAL (O CARROSSEL) ---
// --- 3. MAIN COMPONENT ---
export function TvonePromoStrip() {
const { photos, loading } = useSliderPhotos();
const [index, setIndex] = useState<number>(0);
const [ratios, setRatios] = useState<Record<string, number>>({});
const [reduceMotion, setReduceMotion] = useState<boolean>(false);
// Detetar preferência de movimento do sistema (iOS/MacOS/Windows)
// Constants for the 4.8:1 ratio
const FIXED_RATIO = 4.8 / 1;
useEffect(() => {
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
const sync = () => setReduceMotion(mq.matches);
@@ -88,7 +80,6 @@ export function TvonePromoStrip() {
return () => mq.removeEventListener("change", sync);
}, []);
// Lógica de avanço automático
const advance = useCallback(() => {
if (photos.length <= 1) return;
setIndex((i: number) => (i + 1) % photos.length);
@@ -100,54 +91,46 @@ export function TvonePromoStrip() {
return () => window.clearInterval(id);
}, [photos.length, reduceMotion, advance]);
// Handler para atualizar rácios de imagem
const handleRatio = useCallback((src: string, ratio: number) => {
setRatios((prev) => (prev[src] === ratio ? prev : { ...prev, [src]: ratio }));
}, []);
// Calcula a proporção do contentor baseado no slide ativo
const currentRatio = useMemo<number>(() => {
const activePhoto = photos[index];
return activePhoto ? (ratios[activePhoto.src] || 16 / 9) : 16 / 9;
}, [photos, index, ratios]);
// Loading state with fixed ratio
if (loading && photos.length === 0) {
return <div className="aspect-[16/9] w-full animate-pulse bg-neutral-100 dark:bg-neutral-800" />;
return (
<div
className="w-full animate-pulse bg-neutral-100 dark:bg-neutral-800"
style={{ aspectRatio: "4.8 / 1" }}
/>
);
}
if (photos.length === 0) return null;
return (
<section
className="relative w-full overflow-hidden bg-neutral-100 dark:bg-neutral-900 transition-[aspect-ratio] duration-700 ease-[cubic-bezier(0.32,0.72,0,1)]"
style={{ aspectRatio: currentRatio } as CSSProperties}
className="relative w-full overflow-hidden bg-neutral-100 dark:bg-neutral-900 transition-all duration-700 ease-[cubic-bezier(0.32,0.72,0,1)]"
style={{ aspectRatio: "4.8 / 1" }} // Locked to 4.8:1
role="region"
aria-roledescription="carrossel"
>
{/* O "ROLO" (A fita flexível) */}
{/* THE TRACK */}
<div
className="flex h-full w-full transition-transform duration-1000 ease-[cubic-bezier(0.32,0.72,0,1)]"
style={{ transform: `translateX(-${index * 100}%)` }}
>
{photos.map((photo: SliderPhoto, i: number) => (
<div key={photo.src || i} className="h-full w-full flex-shrink-0">
<PromoStripSingleSlide
photo={photo}
onRatioLoad={handleRatio}
/>
<PromoStripSingleSlide photo={photo} />
</div>
))}
</div>
{/* INDICADORES (iOS Dot Style) */}
{/* INDICATORS */}
{photos.length > 1 && (
<div className="absolute bottom-6 left-1/2 flex -translate-x-1/2 gap-2 z-20">
<div className="absolute bottom-4 left-1/2 flex -translate-x-1/2 gap-2 z-20">
{photos.map((_, i: number) => (
<button
key={i}
onClick={() => setIndex(i)}
className={`h-1.5 transition-all duration-500 ${
index === i ? "w-8 bg-white" : "w-1.5 bg-white/30 hover:bg-white/60"
className={`h-1 transition-all duration-500 ${
index === i ? "w-6 bg-white" : "w-1.5 bg-white/30 hover:bg-white/60"
}`}
aria-label={`Ir para slide ${i + 1}`}
/>
+4 -4
View File
@@ -6,7 +6,7 @@ import { motion } from "framer-motion";
const recentes = [
{
title: "Diddy na XB Label? Gerilson Israel responde após anúncio de nova música em conjunto.",
title: "Diddy na XB Label? Gerilson Israel responde após anúncio de nova música em conjunto",
excerpt: "O artista angolano esclareceu os rumores sobre a sua possível entrada para a editora internacional...",
cat: "Música",
catBg: "bg-blue-50 text-blue-600",
@@ -16,7 +16,7 @@ const recentes = [
img: "https://images.unsplash.com/photo-1598488035139-bdbb2231ce04?q=80&w=800&auto=format&fit=crop",
},
{
title: "Inflação desce pelo terceiro mês consecutivo em Angola, segundo dados preliminares.",
title: "Inflação desce pelo terceiro mês consecutivo em Angola, segundo dados preliminares.,",
excerpt: "Os preços dos bens de consumo registaram uma ligeira queda, trazendo alívio para as famílias...",
cat: "Economia",
catBg: "bg-green-50 text-green-600",
@@ -36,7 +36,7 @@ const recentes = [
img: "https://images.unsplash.com/photo-1507676184212-d03ab07a01bf?q=80&w=800&auto=format&fit=crop",
},
{
title: "Diddy na XB Label? Gerilson Israel responde após anúncio de nova música em conjunto.",
title: "Diddy na XB Label? Gerilson Israel responde após anúncio de nova música em conjunto,",
excerpt: "O artista angolano esclareceu os rumores sobre a sua possível entrada para a editora internacional...",
cat: "Música",
catBg: "bg-blue-50 text-blue-600",
@@ -56,7 +56,7 @@ const recentes = [
img: "https://images.unsplash.com/photo-1526304640581-d334cdbbf45e?q=80&w=800&auto=format&fit=crop",
},
{
title: "Inflação desce pelo terceiro mês consecutivo em Angola, segundo dados preliminares.",
title: "Inflação desce pelo terceiro mês consecutivo em Angola, segundo dados preliminares",
excerpt: "Os preços dos bens de consumo registaram uma ligeira queda, trazendo alívio para as famílias...",
cat: "Economia",
catBg: "bg-green-50 text-green-600",