inicila commit

This commit is contained in:
2026-03-25 14:32:19 +01:00
parent 6ed240b62b
commit 2f9ace4b1c
9 changed files with 671 additions and 85 deletions
+337
View File
@@ -0,0 +1,337 @@
import Image from "next/image";
import Link from "next/link";
const destaques = [
{
cat: "FAMOSOS",
catColor: "text-pink-600",
title: "Cerimónia reúne estrelas nacionais e internacionais em Lisboa.",
date: "24 Mar 2025",
img: "https://images.unsplash.com/photo-1524504388940-b1c1722653e1?w=600&q=80",
},
{
cat: "NEGÓCIOS",
catColor: "text-[#0066cc]",
title: "Mercados reagem às novas projeções de crescimento para a região.",
date: "24 Mar 2025",
img: "https://images.unsplash.com/photo-1486406146926-c627a92ad4ab?w=600&q=80",
},
{
cat: "DESPORTO",
catColor: "text-emerald-600",
title: "Taça: equipa da casa garante lugar nas meias com exibição sólida.",
date: "23 Mar 2025",
img: "https://images.unsplash.com/photo-1574629810360-7efbbe195018?w=600&q=80",
},
{
cat: "TECNOLOGIA",
catColor: "text-violet-600",
title: "Novos dispositivos chegam às lojas com foco em sustentabilidade.",
date: "23 Mar 2025",
img: "https://images.unsplash.com/photo-1518770660439-4636190af475?w=600&q=80",
},
];
const recentes = [
{
cat: "EM FOCO",
catBg: "bg-pink-100 text-pink-700",
title: "Governo anuncia medidas para apoiar famílias e pequenas empresas.",
excerpt: "Pacote inclui linhas de crédito e simplificação de procedimentos.",
byline: "Por Redação",
date: "24 Mar 2025",
img: "https://images.unsplash.com/photo-1507679799987-c73779587ccf?w=200&q=80",
},
{
cat: "ECONOMIA",
catBg: "bg-amber-100 text-amber-800",
title: "Inflação desce pelo terceiro mês consecutivo, segundo dados preliminares.",
excerpt: "Analistas mantêm cautela face ao cenário internacional.",
byline: "Por Economia",
date: "24 Mar 2025",
img: "https://images.unsplash.com/photo-1611974789855-9c2a0a7236a3?w=200&q=80",
},
{
cat: "CULTURA",
catBg: "bg-violet-100 text-violet-800",
title: "Museu inaugura exposição com obras inéditas de artistas locais.",
excerpt: "Visitas guiadas e programa educativo arrancam no próximo fim de semana.",
byline: "Por Cultura",
date: "23 Mar 2025",
img: "https://images.unsplash.com/photo-1549887534-1541e9326642?w=200&q=80",
},
{
cat: "SAÚDE",
catBg: "bg-emerald-100 text-emerald-800",
title: "Campanha de vacinação alarga faixas etárias em todo o país.",
excerpt: "Autoridades de saúde reforçam importância da adesão às janelas recomendadas.",
byline: "Por Saúde",
date: "23 Mar 2025",
img: "https://images.unsplash.com/photo-1576091160399-112ba8d25d1d?w=200&q=80",
},
];
const aSeguir = [
{
title: "Mercado imobiliário: especialistas explicam tendências para 2025.",
date: "23 Mar",
img: "https://images.unsplash.com/photo-1560518883-ce09059eeffa?w=120&q=80",
},
{
title: "Cinema: estreia nacional bate recordes de bilheteira no primeiro fim de semana.",
date: "22 Mar",
img: "https://images.unsplash.com/photo-1489599849927-2ee91cede3ba?w=120&q=80",
},
{
title: "Ambiente: projeto de reflorestação ultrapassa meta anual em três meses.",
date: "22 Mar",
img: "https://images.unsplash.com/photo-1448375240586-882707db888d?w=120&q=80",
},
];
export function TvoneDestaques() {
return (
<section className="mx-auto w-full max-w-[1200px] px-4 pb-10">
<h2 className="mb-5 text-xl font-bold tracking-tight text-neutral-900">Destaques</h2>
<div className="grid gap-5 sm:grid-cols-2 lg:grid-cols-4">
{destaques.map((item) => (
<article
key={item.title}
className="group overflow-hidden rounded-xl border border-neutral-200/80 bg-white shadow-sm transition hover:shadow-md"
>
<Link href="#" className="block">
<div className="relative aspect-[4/3] w-full overflow-hidden">
<Image
src={item.img}
alt=""
fill
className="object-cover transition duration-300 group-hover:scale-[1.03]"
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 25vw"
/>
</div>
<div className="p-4">
<p className={`mb-2 text-[11px] font-bold uppercase tracking-wide ${item.catColor}`}>{item.cat}</p>
<h3 className="text-[15px] font-semibold leading-snug text-neutral-900">{item.title}</h3>
<p className="mt-3 text-xs text-neutral-500">{item.date}</p>
</div>
</Link>
</article>
))}
</div>
</section>
);
}
export function TvoneMainColumns() {
return (
<div className="mx-auto grid w-full max-w-[1200px] gap-10 px-4 pb-12 lg:grid-cols-[1fr_340px]">
<section>
<h2 className="mb-6 text-xl font-bold tracking-tight text-neutral-900">Mais Recentes</h2>
<ul className="flex flex-col gap-6">
{recentes.map((item) => (
<li key={item.title}>
<Link href="#" className="group flex gap-4 rounded-xl border border-transparent p-1 transition hover:border-neutral-200 hover:bg-neutral-50">
<div className="relative h-24 w-28 shrink-0 overflow-hidden rounded-lg sm:h-28 sm:w-36">
<Image src={item.img} alt="" fill className="object-cover" sizes="144px" />
</div>
<div className="min-w-0 flex-1">
<span className={`inline-block rounded px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide ${item.catBg}`}>
{item.cat}
</span>
<h3 className="mt-2 text-base font-semibold leading-snug text-neutral-900 group-hover:text-[#0066cc]">
{item.title}
</h3>
<p className="mt-1 line-clamp-2 text-sm text-neutral-600">{item.excerpt}</p>
<p className="mt-2 text-xs text-neutral-500">
{item.byline} · {item.date}
</p>
</div>
</Link>
</li>
))}
</ul>
<Link
href="#"
className="mt-8 flex w-full items-center justify-center rounded-xl bg-[#f5f5f7] py-3 text-sm font-medium text-neutral-800 transition hover:bg-neutral-200/80"
>
Ver todas as notícias
</Link>
</section>
<aside className="flex flex-col gap-8">
<div className="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm">
<div className="flex items-center gap-2 border-b border-neutral-100 px-4 py-3">
<svg className="h-5 w-5 text-neutral-800" viewBox="0 0 24 24" fill="currentColor" aria-hidden>
<path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z" />
</svg>
<span className="text-sm font-semibold text-neutral-800">Apple Line</span>
</div>
<div className="relative aspect-[16/10] w-full">
<Image
src="https://images.unsplash.com/photo-1486406146926-c627a92ad4ab?w=680&q=80"
alt=""
fill
className="object-cover"
sizes="340px"
/>
</div>
<div className="p-4">
<span className="text-[11px] font-bold uppercase tracking-wide text-[#0066cc]">Bancos</span>
<h3 className="mt-2 text-lg font-bold leading-snug text-neutral-900">
BAI regista lucros acima das expectativas no último trimestre.
</h3>
<p className="mt-2 text-xs text-neutral-500">24 Mar 2025</p>
<Link
href="#"
className="mt-4 flex w-full items-center justify-center rounded-lg bg-neutral-900 py-2.5 text-sm font-medium text-white transition hover:bg-neutral-800"
>
Ver Página Apple Line
</Link>
</div>
</div>
<div>
<h3 className="mb-4 text-lg font-bold text-neutral-900">A seguir</h3>
<ul className="flex flex-col gap-4">
{aSeguir.map((item) => (
<li key={item.title}>
<Link href="#" className="group flex gap-3">
<div className="relative h-16 w-16 shrink-0 overflow-hidden rounded-lg">
<Image src={item.img} alt="" fill className="object-cover" sizes="64px" />
</div>
<div className="min-w-0">
<p className="text-sm font-medium leading-snug text-neutral-900 group-hover:text-[#0066cc]">{item.title}</p>
<p className="mt-1 text-xs text-neutral-500">{item.date}</p>
</div>
</Link>
</li>
))}
</ul>
</div>
</aside>
</div>
);
}
export function TvoneAdBanner() {
return (
<section className="mx-auto w-full max-w-[1200px] px-4 pb-10">
<div className="relative overflow-hidden rounded-xl bg-gradient-to-r from-[#0a4d8c] via-[#1e6fb8] to-[#e85c2a] px-6 py-8 text-white md:flex md:items-center md:justify-between md:py-10">
<div className="max-w-lg">
<p className="text-[11px] font-semibold uppercase tracking-widest text-white/90">BAI Directo</p>
<h2 className="mt-2 text-2xl font-bold md:text-3xl">Actualização do BAI Directo</h2>
<p className="mt-2 text-sm text-white/90">Faça as suas operações com mais rapidez e segurança em qualquer dispositivo.</p>
</div>
<div className="relative mt-6 h-32 w-full max-w-xs shrink-0 md:mt-0 md:h-36">
<Image
src="https://images.unsplash.com/photo-1511707171634-5f897ff02aa9?w=400&q=80"
alt=""
fill
className="object-contain object-right"
sizes="320px"
/>
</div>
<span className="absolute right-6 top-1/2 hidden -translate-y-1/2 text-2xl font-black tracking-tight opacity-90 md:block">
BAI
</span>
</div>
</section>
);
}
const services = [
{ icon: "truck", label: "Entrega gratuita" },
{ icon: "return", label: "Devoluções fáceis" },
{ icon: "shield", label: "Pagamento seguro" },
{ icon: "headset", label: "Apoio 24/7" },
];
function ServiceIcon({ name }: { name: string }) {
const common = "h-6 w-6 text-neutral-600";
switch (name) {
case "truck":
return (
<svg className={common} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M9 17a2 2 0 11-4 0 2 2 0 014 0zM19 17a2 2 0 11-4 0 2 2 0 014 0z" />
<path d="M13 16V6a1 1 0 00-1-1H4a1 1 0 00-1 1v10a1 1 0 001 1h1m8-1a1 1 0 01-1 1H9m4-1V8a1 1 0 011-1h2.586a1 1 0 01.707.293l3.414 3.414a1 1 0 01.293.707V16a1 1 0 01-1 1h-1m-6-1a1 1 0 001 1h1M5 17a2 2 0 104 0m-4 0a2 2 0 114 0m6 0a2 2 0 104 0m-4 0a2 2 0 114 0" />
</svg>
);
case "return":
return (
<svg className={common} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5">
<path d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
);
case "shield":
return (
<svg className={common} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5">
<path d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
);
case "headset":
return (
<svg className={common} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5">
<path d="M19 14v3a2 2 0 01-2 2h-2v-6h2a2 2 0 012 2zm-8 5H7a2 2 0 01-2-2v-3a2 2 0 012-2h2v7z" />
<path d="M5 14v-1a7 7 0 0114 0v1" strokeLinecap="round" />
</svg>
);
default:
return null;
}
}
export function TvoneServiceStrip() {
return (
<div className="border-y border-neutral-200 bg-[#f5f5f7] py-6">
<div className="mx-auto flex max-w-[1200px] flex-wrap items-center justify-center gap-8 px-4 md:justify-between md:gap-4">
{services.map((s) => (
<div key={s.label} className="flex items-center gap-3 text-sm text-neutral-700">
<ServiceIcon name={s.icon} />
<span className="font-medium">{s.label}</span>
</div>
))}
</div>
</div>
);
}
export function TvoneFooter() {
return (
<footer className="border-t border-neutral-200 bg-white py-10">
<div className="mx-auto flex max-w-[1200px] flex-col gap-8 px-4 md:flex-row md:items-center md:justify-between">
<div>
<p className="text-lg font-bold tracking-tight text-neutral-900">PLATINALINE</p>
<p className="mt-1 text-sm text-neutral-500">© 2025 PlatinaLine. Todos os direitos reservados.</p>
</div>
<nav className="flex flex-wrap gap-x-6 gap-y-2 text-sm text-neutral-600">
<Link href="#" className="hover:text-neutral-900">
Privacidade
</Link>
<Link href="#" className="hover:text-neutral-900">
Termos de Uso
</Link>
<Link href="#" className="hover:text-neutral-900">
Publicidade
</Link>
<Link href="#" className="hover:text-neutral-900">
Contactos
</Link>
</nav>
<div className="flex items-center gap-4 text-neutral-500">
<Link href="#" aria-label="Facebook" className="hover:text-neutral-800">
f
</Link>
<Link href="#" aria-label="Instagram" className="hover:text-neutral-800">
in
</Link>
<Link href="#" aria-label="YouTube" className="hover:text-neutral-800">
</Link>
<Link href="#" aria-label="X" className="hover:text-neutral-800">
𝕏
</Link>
</div>
</div>
</footer>
);
}
+143
View File
@@ -0,0 +1,143 @@
import Image from "next/image";
import Link from "next/link";
const PROMO_IMG_LEFT =
"https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=800&q=80&auto=format&fit=crop";
const PROMO_IMG_RIGHT =
"https://images.unsplash.com/photo-1544367567-0f2fcb009e0b?w=800&q=80&auto=format&fit=crop";
const appleNav = [
"Loja",
"Mac",
"iPad",
"iPhone",
"Watch",
"AirPods",
"TV e Casa",
"Entretenimento",
"Acessórios",
"Suporte",
];
function AppleLogo({ className }: { className?: string }) {
return (
<svg aria-hidden className={className} viewBox="0 0 24 24" fill="currentColor">
<path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z" />
</svg>
);
}
function SearchIcon({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 15 15" width="15" height="15" fill="none" stroke="currentColor" strokeWidth="1.2">
<circle cx="6.5" cy="6.5" r="5" />
<path d="M10 10l3.5 3.5" strokeLinecap="round" />
</svg>
);
}
function BagIcon({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" strokeWidth="1.5">
<path d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" strokeLinejoin="round" />
</svg>
);
}
export function TvoneHeader() {
return (
<header className="w-full">
<nav
className="flex h-11 items-center justify-center gap-1 bg-[#1d1d1f] px-4 text-[12px] font-normal text-[#f5f5f7] md:gap-2 md:text-[13px]"
aria-label="Navegação principal"
>
<div className="flex w-full max-w-[980px] items-center justify-between gap-2">
<Link href="/" className="opacity-90 hover:opacity-100" aria-label="Apple">
<AppleLogo className="h-5 w-5 text-white md:h-[22px] md:w-[22px]" />
</Link>
<ul className="hidden flex-1 items-center justify-center gap-4 lg:flex xl:gap-6">
{appleNav.map((item) => (
<li key={item}>
<Link href="#" className="whitespace-nowrap opacity-90 hover:opacity-100">
{item}
</Link>
</li>
))}
</ul>
<div className="flex items-center gap-5">
<button type="button" className="opacity-90 hover:opacity-100" aria-label="Pesquisar">
<SearchIcon className="text-white" />
</button>
<button type="button" className="opacity-90 hover:opacity-100" aria-label="Sacola">
<BagIcon className="text-white" />
</button>
</div>
</div>
</nav>
<div className="relative flex min-h-[148px] w-full overflow-hidden bg-[#9d1f55] text-white sm:min-h-[180px] md:min-h-[204px] lg:min-h-[228px]">
<div className="relative w-[22%] min-w-[80px] max-w-[300px] shrink-0 sm:w-[24%] md:w-[26%]">
<Image
src={PROMO_IMG_LEFT}
alt="Mulher em atividade ao ar livre"
fill
className="object-cover object-[center_28%]"
sizes="(max-width: 640px) 28vw, 300px"
priority
/>
<div
className="absolute inset-0 bg-gradient-to-r from-black/35 from-[8%] via-[#b8326a]/88 via-[55%] to-[#b8326a]"
aria-hidden
/>
</div>
<div className="relative z-[1] flex min-w-0 flex-1 flex-col justify-center gap-3 bg-gradient-to-r from-[#b8326a] via-[#d9468f] to-[#b8326a] px-4 py-6 sm:flex-row sm:items-center sm:justify-between sm:gap-6 sm:px-7 sm:py-7 md:gap-10 md:px-9 md:py-8 lg:px-10">
<div className="flex min-w-0 flex-col gap-2 sm:flex-row sm:items-center sm:gap-5 md:gap-9">
<span className="shrink-0 text-[11px] font-semibold uppercase tracking-[0.2em] text-white/95 sm:text-xs">
Nossa Seguros
</span>
<p className="text-pretty text-sm font-medium leading-relaxed text-white sm:text-base md:text-lg lg:max-w-[40rem] lg:leading-relaxed">
Seguro Saúde Mulher cuidado que acompanha o seu ritmo.
</p>
</div>
<div className="flex shrink-0 items-center gap-4 text-white/95 sm:pl-2">
<span className="sr-only">Redes sociais</span>
<Link href="#" className="text-sm hover:opacity-80" aria-label="Facebook">
f
</Link>
<Link href="#" className="text-sm hover:opacity-80" aria-label="LinkedIn">
in
</Link>
<Link href="#" className="text-sm hover:opacity-80" aria-label="Instagram">
</Link>
</div>
</div>
<div className="relative w-[22%] min-w-[80px] max-w-[300px] shrink-0 sm:w-[24%] md:w-[26%]">
<Image
src={PROMO_IMG_RIGHT}
alt="Bem-estar e cuidados de saúde"
fill
className="object-cover object-[center_38%]"
sizes="(max-width: 640px) 28vw, 300px"
priority
/>
<div
className="absolute inset-0 bg-gradient-to-l from-black/35 from-[8%] via-[#b8326a]/88 via-[55%] to-[#b8326a]"
aria-hidden
/>
</div>
</div>
<div className="border-b border-[#0066cc]/20 bg-[#0066cc] py-2">
<div className="mx-auto flex max-w-[1200px] items-center gap-3 px-4">
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-white text-sm font-bold tracking-tight text-[#0066cc]">
tv
</div>
<span className="text-lg font-semibold tracking-tight text-white">tvone</span>
</div>
</div>
</header>
);
}
+76
View File
@@ -0,0 +1,76 @@
"use client";
import Image from "next/image";
import { useState } 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.",
byline: "Por Redação — 24 de Março, 2025",
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",
},
{
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",
},
];
export function TvoneHero() {
const [active, setActive] = useState(0);
const slide = slides[active]!;
return (
<section className="mx-auto w-full max-w-[1200px] px-4 py-6">
<div className="relative overflow-hidden rounded-xl shadow-[0_12px_40px_rgba(0,0,0,0.12)]">
<div className="relative aspect-[21/9] min-h-[280px] w-full md:aspect-[2.4/1]">
<Image
src={slide.image}
alt=""
fill
className="object-cover"
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 rounded bg-[#7c3aed] px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide 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}
/>
))}
</div>
</div>
</section>
);
}
@@ -0,0 +1,73 @@
import Image from "next/image";
import Link from "next/link";
export type TvonePublicationBannerProps = {
/** When set, the whole slot links here (campaign URL). */
href?: string;
/** Optional creative — leaderboard-style wide image (e.g. 970×90 or similar). */
imageSrc?: string;
imageAlt?: string;
/** Short line shown when no image (placeholder for unsold inventory). */
title?: string;
subtitle?: string;
/** Small label above the slot (legal / transparency). */
slotLabel?: string;
};
export function TvonePublicationBanner({
href = "#publicidade",
imageSrc,
imageAlt = "Publicidade",
title = "Espaço publicitário",
subtitle = "Reserve este espaço para a sua marca. Contacte a nossa equipa comercial.",
slotLabel = "Publicidade",
}: TvonePublicationBannerProps) {
const inner = imageSrc ? (
<Image
src={imageSrc}
alt={imageAlt}
width={1200}
height={120}
className="h-auto w-full max-h-[120px] object-cover object-center md:max-h-[140px]"
sizes="100vw"
priority
/>
) : (
<div className="flex min-h-[88px] w-full flex-col items-center justify-center gap-1 bg-[#f0f0f3] px-4 py-5 text-center md:min-h-[100px] md:flex-row md:justify-between md:text-left">
<div>
<p className="text-sm font-semibold text-neutral-800">{title}</p>
<p className="mt-0.5 max-w-xl text-xs text-neutral-600 md:text-sm">{subtitle}</p>
</div>
<span className="mt-2 shrink-0 rounded-full border border-neutral-300 bg-white px-3 py-1 text-[11px] font-medium text-neutral-700 md:mt-0">
Espaço disponível
</span>
</div>
);
return (
<aside
className="w-full border-y border-neutral-200/90 bg-white"
aria-label={slotLabel}
>
<div className="mx-auto w-full max-w-[1200px] px-0">
<div className="flex items-center gap-2 px-4 pt-2 pb-1">
<span className="text-[10px] font-semibold uppercase tracking-wider text-neutral-400">{slotLabel}</span>
</div>
<div className="overflow-hidden">
{href ? (
<Link
href={href}
className="block w-full outline-none transition-opacity hover:opacity-95 focus-visible:ring-2 focus-visible:ring-[#0066cc] focus-visible:ring-offset-2"
target={href.startsWith("http") ? "_blank" : undefined}
rel={href.startsWith("http") ? "noopener noreferrer" : undefined}
>
{inner}
</Link>
) : (
inner
)}
</div>
</div>
</aside>
);
}
+5 -10
View File
@@ -3,24 +3,19 @@
:root {
--background: #ffffff;
--foreground: #171717;
--tvone-blue: #0066cc;
--tvone-magenta: #d9468f;
--tvone-muted: #f5f5f7;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
--font-sans: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
font-family: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
}
+11 -15
View File
@@ -1,20 +1,15 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { Inter } from "next/font/google";
import "./globals.css";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
const inter = Inter({
variable: "--font-inter",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "tvone — Notícias e entretenimento",
description: "O seu portal de notícias, música e cultura.",
};
export default function RootLayout({
@@ -23,11 +18,12 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html
lang="en"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col">{children}</body>
<html lang="pt" className={`${inter.variable} h-full antialiased`}>
<body
className={`min-h-full flex flex-col bg-white text-neutral-900 ${inter.className}`}
>
{children}
</body>
</html>
);
}
+17 -59
View File
@@ -1,65 +1,23 @@
import Image from "next/image";
import { TvoneHeader } from "./components/tvone-header";
import { TvoneHero } from "./components/tvone-hero";
import {
TvoneAdBanner,
TvoneDestaques,
TvoneFooter,
TvoneMainColumns,
TvoneServiceStrip,
} from "./components/tvone-content";
export default function Home() {
return (
<div className="flex flex-col flex-1 items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex flex-1 w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the page.tsx file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{" "}
center.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={16}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
</div>
</main>
<div className="flex min-h-full flex-col bg-white">
<TvoneHeader />
<TvoneHero />
<TvoneDestaques />
<TvoneMainColumns />
<TvoneAdBanner />
<TvoneServiceStrip />
<TvoneFooter />
</div>
);
}
+9 -1
View File
@@ -1,7 +1,15 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
images: {
remotePatterns: [
{
protocol: "https",
hostname: "images.unsplash.com",
pathname: "/**",
},
],
},
};
export default nextConfig;
Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB