67656fa32d
Se añade la integración del script de Monetag (MultiTag: popunder + push + in-page push + vignette) como alternativa a AdSense para monetizar sin depender de que Google apruebe el sitio. Tres interruptores (ver components/Monetag.tsx): 1. `MONETAG_SRC` + `MONETAG_ZONE` en el .env (no versionadas, documentadas en el README). Cualquiera de las dos vacía = no se carga nada. Se leen en el servidor y se pasan como props, así que encender/apagar es tocar el .env + reiniciar, SIN rebuild. Ahora mismo van vacías: la integración queda instalada pero inerte hasta que se pegue la zona del panel de Monetag. 2. El filtro común de publicidad, extraído a lib/ads.ts (`shouldServeAds`): fuera para admins y para quien sea rango 2+ o haya pagado alguna vez. Antes esta lógica vivía dentro de AdSense.tsx; ahora la comparten la etiqueta de AdSense y el script de Monetag desde un único sitio, para que no se puedan desincronizar. 3. El consentimiento «Marketing» del banner, en components/MonetagScript.tsx (cliente). A diferencia de la etiqueta de AdSense, MultiTag escribe cookies y pide permisos, así que NO puede cargarse sin aceptar la categoría. Mismo patrón que Analytics.tsx: useConsent reacciona en caliente, arranca en false. El push de MultiTag necesitará además un sw.js servido desde la raíz del dominio (public/sw.js, descargado del panel). Sin él, el resto de formatos funcionan igual. Verificado: con las variables vacías la web queda idéntica (ni script de Monetag ni cambios) y la etiqueta de AdSense sigue intacta. Con una zona de prueba, el filtro de servidor deja pasar a anónimos y rango 1 sin pagos, y corta a los admins. Sin consentimiento no se inyecta ningún <script> (la zona solo viaja como prop inerte en el payload de React). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
115 lines
4.7 KiB
TypeScript
115 lines
4.7 KiB
TypeScript
import type { Metadata } from 'next'
|
|
import Script from 'next/script'
|
|
import { notFound } from 'next/navigation'
|
|
import { NextIntlClientProvider, hasLocale } from 'next-intl'
|
|
import { getTranslations, setRequestLocale } from 'next-intl/server'
|
|
import { routing } from '@/i18n/routing'
|
|
import { Header } from '@/components/Header'
|
|
import { Video } from '@/components/Video'
|
|
import { Social } from '@/components/Social'
|
|
import { Footer } from '@/components/Footer'
|
|
import { CookieBanner } from '@/components/CookieConsent'
|
|
import { Analytics } from '@/components/Analytics'
|
|
import { AdSense } from '@/components/AdSense'
|
|
import { Monetag } from '@/components/Monetag'
|
|
import '../globals.css'
|
|
|
|
export function generateStaticParams() {
|
|
return routing.locales.map((locale) => ({ locale }))
|
|
}
|
|
|
|
// SEO por idioma (SSR) vía Metadata API.
|
|
export async function generateMetadata({
|
|
params,
|
|
}: {
|
|
params: Promise<{ locale: string }>
|
|
}): Promise<Metadata> {
|
|
const { locale } = await params
|
|
const t = await getTranslations({ locale, namespace: 'Metadata' })
|
|
return {
|
|
title: t('title'),
|
|
description: t('description'),
|
|
openGraph: {
|
|
siteName: 'NightSpire',
|
|
title: t('title'),
|
|
description: t('description'),
|
|
type: 'website',
|
|
locale: locale === 'es' ? 'es_ES' : 'en_US',
|
|
url: 'https://www.nightspire.gg/',
|
|
},
|
|
}
|
|
}
|
|
|
|
export default async function LocaleLayout({
|
|
children,
|
|
params,
|
|
}: {
|
|
children: React.ReactNode
|
|
params: Promise<{ locale: string }>
|
|
}) {
|
|
const { locale } = await params
|
|
if (!hasLocale(routing.locales, locale)) notFound()
|
|
setRequestLocale(locale)
|
|
|
|
return (
|
|
<html lang={locale}>
|
|
<head>
|
|
{/* Verificación de la cuenta de Google AdSense: solo si hay ADSENSE_CLIENT_ID
|
|
y el visitante no es admin. Ver components/AdSense.tsx. */}
|
|
<AdSense />
|
|
{/* Iconos del sitio (idénticos a la web Django) */}
|
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
|
<link rel="icon" type="image/png" sizes="194x194" href="/favicon-194x194.png" />
|
|
<link rel="icon" type="image/png" sizes="192x192" href="/android-chrome-192x192.png" />
|
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
|
<link rel="manifest" href="/site.webmanifest" />
|
|
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#47210a" />
|
|
<link rel="shortcut icon" href="/favicon.ico" />
|
|
{/* Font Awesome (mismos iconos que la web Django) */}
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css"
|
|
/>
|
|
{/* Config de los tooltips de wowhead (debe definirse antes de tooltips.js).
|
|
OJO con el `window.`: tooltips.js lee `window.whTooltips`, y un `const` a
|
|
nivel de script queda en el ámbito léxico del script (no crea propiedad en
|
|
window), así que la config se ignoraba entera y valían los valores por
|
|
defecto de wowhead.
|
|
`colorLinks` tiñe cada enlace según la calidad del ítem e `iconizeLinks` le
|
|
antepone el icono pequeño: los dos replican lo que hace el store original
|
|
(sus enlaces acaban con las clases `icontinyl q4`). Sin colorLinks los
|
|
nombres caen al `a{color:#2471a9}` del tema y salen todos azules.
|
|
`renameLinks` NO: el texto de los enlaces es el nombre de nuestra BD (en
|
|
español), y wowhead lo sobreescribiría. El idioma del tooltip lo da el
|
|
subdominio del enlace (es./www.). */}
|
|
<script
|
|
dangerouslySetInnerHTML={{
|
|
__html: 'window.whTooltips={colorLinks:true,iconizeLinks:true,renameLinks:false};',
|
|
}}
|
|
/>
|
|
</head>
|
|
<body>
|
|
<NextIntlClientProvider>
|
|
<Header />
|
|
<Video />
|
|
{children}
|
|
<Social />
|
|
<Footer />
|
|
<CookieBanner />
|
|
</NextIntlClientProvider>
|
|
{/* Analítica: solo si hay NEXT_PUBLIC_GA_ID y el visitante ha aceptado
|
|
la categoría «Analíticas» del banner. Ver components/Analytics.tsx. */}
|
|
<Analytics />
|
|
{/* Anuncios de Monetag: solo si hay MONETAG_SRC + MONETAG_ZONE, el visitante
|
|
no es admin ni ha pagado, y ha aceptado «Marketing». Ver components/Monetag.tsx. */}
|
|
<Monetag />
|
|
{/* Tooltips de wowhead (WotLK) en todos los enlaces .../wowhead.com/... y
|
|
elementos con data-wowhead. Funciona con contenido añadido por React
|
|
(carrito, búsquedas) porque delega el hover en el documento. */}
|
|
<Script src="https://wow.zamimg.com/js/tooltips.js" strategy="afterInteractive" />
|
|
</body>
|
|
</html>
|
|
)
|
|
}
|