Revisão Logo, Favicon, Robots

This commit is contained in:
2026-05-30 23:54:48 -03:00
parent 3e91269f12
commit 4e26c13240
105 changed files with 8137 additions and 693 deletions
+13 -10
View File
@@ -1,31 +1,34 @@
import { useState } from 'react';
import { AlertTriangle, X } from 'lucide-react';
import { IS_HOMOLOGATION } from '@/config/mautic';
import { ENV_CONFIG, IS_PRODUCTION } from '../config/environment';
/**
* Banner visual que aparece em ambiente de homologacao
* Avisa que Mautic, Google Ads e Facebook Pixel estao em modo simulacao
* Banner visual que aparece em ambiente NAO-producao
* Avisa qual ambiente esta rodando
*/
export default function HomologationBanner() {
export default function AmbientBanner() {
const [dismissed, setDismissed] = useState(false);
if (!IS_HOMOLOGATION || dismissed) return null;
// So mostra em producao
if (IS_PRODUCTION || dismissed) return null;
const { bannerText, bannerColor } = ENV_CONFIG;
return (
<div className="fixed bottom-4 right-4 z-[100] max-w-md">
<div className="bg-amber-500 text-[#0e0e0e] rounded-xl shadow-2xl p-4 border-2 border-amber-400">
<div className={`${bannerColor} text-[#0e0e0e] rounded-xl shadow-2xl p-4 border-2 border-white/20`}>
<div className="flex items-start gap-3">
<AlertTriangle className="w-5 h-5 shrink-0 mt-0.5" />
<div className="flex-1">
<p className="font-bold text-sm">Ambiente de Homologacao</p>
<p className="font-bold text-sm">Ambiente: {bannerText}</p>
<p className="text-xs mt-1 opacity-90">
Mautic, Google Ads e Facebook Pixel estao em modo <strong>simulacao</strong>.
Nenhum dado real e enviado. Verifique o console (F12) para ver o que seria enviado.
Tracking desativado | SEO: noindex |
Nenhum dado enviado a Mautic, GA4, Ads ou Pixel.
</p>
</div>
<button
onClick={() => setDismissed(true)}
className="shrink-0 p-1 hover:bg-amber-600 rounded-lg transition-colors"
className="shrink-0 p-1 hover:bg-black/20 rounded-lg transition-colors"
aria-label="Fechar"
>
<X className="w-4 h-4" />
+121
View File
@@ -0,0 +1,121 @@
// ============================================================================
// SEO - Meta tags dinamicas por pagina
// ============================================================================
// Uso: <SEO title="..." description="..." />
//
// Cada pagina deve usar este componente com suas proprias tags.
// O canonical e gerado automaticamente a partir da URL atual.
// ============================================================================
import { Helmet } from 'react-helmet-async';
import { useLocation } from 'react-router-dom';
import { ENV_CONFIG } from '../config/environment';
interface SEOProps {
title?: string;
description?: string;
keywords?: string;
ogImage?: string;
ogType?: string;
noindex?: boolean; // Se true, forca noindex mesmo em producao
schema?: Record<string, any>;
}
const SITE_URL = 'https://avanzato.com.br';
const DEFAULT_TITLE = 'Avanzato Tecnologia | TI Gerenciada, Cloud e Seguranca';
const DEFAULT_DESC = 'Solucoes em TI Gerenciada, Cloud Computing e Seguranca da Informacao. +23 anos de experiencia, +500 clientes atendidos. Suporte 24/7 em Guarulhos e regiao.';
const DEFAULT_OG_IMAGE = 'https://avanzato.com.br/og-image.jpg';
export default function SEO({
title,
description,
keywords,
ogImage,
ogType = 'website',
noindex = false,
schema,
}: SEOProps) {
const location = useLocation();
const pathname = location.pathname;
const canonicalUrl = `${SITE_URL}${pathname}`;
const fullTitle = title ? `${title} | Avanzato` : DEFAULT_TITLE;
return (
<Helmet>
{/* Title */}
<title>{fullTitle}</title>
<meta name="title" content={fullTitle} />
{/* Description */}
{description && <meta name="description" content={description} />}
{!description && <meta name="description" content={DEFAULT_DESC} />}
{/* Keywords */}
{keywords && <meta name="keywords" content={keywords} />}
{/* Canonical - DINAMICO por pagina */}
<link rel="canonical" href={canonicalUrl} />
{/* Robots - automatico por ambiente, override com prop noindex */}
{noindex || !ENV_CONFIG.allowIndexing ? (
<meta name="robots" content="noindex, nofollow" />
) : (
<meta name="robots" content="index, follow" />
)}
{/* Open Graph */}
<meta property="og:type" content={ogType} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:title" content={fullTitle} />
<meta property="og:description" content={description || DEFAULT_DESC} />
<meta property="og:image" content={ogImage || DEFAULT_OG_IMAGE} />
<meta property="og:locale" content="pt_BR" />
<meta property="og:site_name" content="Avanzato Tecnologia" />
{/* Twitter */}
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={canonicalUrl} />
<meta property="twitter:title" content={fullTitle} />
<meta property="twitter:description" content={description || DEFAULT_DESC} />
<meta property="twitter:image" content={ogImage || DEFAULT_OG_IMAGE} />
{/* Schema.org */}
{schema && (
<script type="application/ld+json">
{JSON.stringify(schema)}
</script>
)}
</Helmet>
);
}
// Schema helpers
export const createServiceSchema = (name: string, description: string, urlPath: string) => ({
'@context': 'https://schema.org',
'@type': 'Service',
name,
description,
provider: {
'@type': 'Organization',
name: 'Avanzato Tecnologia',
url: SITE_URL,
},
url: `${SITE_URL}${urlPath}`,
areaServed: {
'@type': 'City',
name: 'Guarulhos',
},
});
export const createFAQSchema = (questions: Array<{q: string; a: string}>) => ({
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: questions.map(({q, a}) => ({
'@type': 'Question',
name: q,
acceptedAnswer: {
'@type': 'Answer',
text: a,
},
})),
});