feat(config, layout, components): enhance security headers, improve SEO, and update project descriptions
- Added security headers in the Next.js configuration to enhance application security. - Updated metadata in the layout component for improved SEO, including new titles, descriptions, and keywords. - Introduced JSON-LD schema for projects to enhance search engine visibility. - Enhanced project descriptions in the portfolio data for clarity and detail. - Improved header component with logo integration and refined social media links for better accessibility.
This commit is contained in:
1 parent
3f3fca11ab
commit
ad6a76efdd
14 files changed
+467
-57
No files matched your search
@@ -138,6 +138,16 @@ export default function About() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* SEO Semantic Content - Visible but subtle */}
|
||||
<div className="mt-16 pt-8 border-t border-slate-800">
|
||||
<p className="text-xs text-slate-600 text-center max-w-2xl mx-auto leading-relaxed">
|
||||
Evandro Fonseca Junior é Engenheiro Full-Stack especializado em Next.js,
|
||||
React, Angular e Node.js. Desenvolvedor de aplicações desktop com Tauri,
|
||||
sistemas web escaláveis e automação de processos. Experiência em PostgreSQL,
|
||||
MySQL, computação em nuvem e IoT. Localizado em Garuva, Santa Catarina, Brasil.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { MenuIcon, XIcon, Layers } from "lucide-react";
|
||||
import { MenuIcon, XIcon } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
// Definição de Tipos para consistência de dados
|
||||
@@ -59,8 +60,15 @@ export function Header() {
|
||||
whileHover={{ scale: 1.05 }}
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
>
|
||||
<div className="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center shadow-[0_0_15px_rgba(37,99,235,0.4)]">
|
||||
<Layers className="w-5 h-5 text-white" />
|
||||
<div className="w-8 h-8 flex items-center justify-center">
|
||||
<Image
|
||||
src="/edev_logo.svg"
|
||||
alt="Evandro.dev Logo"
|
||||
width={32}
|
||||
height={32}
|
||||
className="w-8 h-8"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
<span className="text-xl font-black tracking-tighter text-white">
|
||||
EVANDRO<span className="text-blue-500">.DEV</span>
|
||||
|
||||
+13
-6
@@ -21,7 +21,7 @@ export default function Hero() {
|
||||
};
|
||||
|
||||
return (
|
||||
<section id="home" className="relative min-h-screen flex items-center justify-center overflow-hidden bg-[#030712]">
|
||||
<section id="home" className="relative min-h-screen flex items-center justify-center overflow-hidden bg-[#030712] pt-28 md:pt-20">
|
||||
{/* 1. Background Engineering: Grid Pattern & Radial Shading */}
|
||||
<div className="absolute inset-0 z-0">
|
||||
<div className="absolute inset-0 bg-[linear-gradient(to_right,#1f2937_1px,transparent_1px),linear-gradient(to_bottom,#1f2937_1px,transparent_1px)] bg-[size:4rem_4rem] [mask-image:radial-gradient(ellipse_60%_50%_at_50%_0%,#000_70%,transparent_100%)] opacity-20" />
|
||||
@@ -79,11 +79,17 @@ export default function Hero() {
|
||||
|
||||
<div className="flex gap-4 px-4">
|
||||
{[
|
||||
{ icon: Github, link: "https://github.com/evandrodevbr" },
|
||||
{ icon: Linkedin, link: "https://linkedin.com/..." },
|
||||
{ icon: Mail, link: "mailto:..." }
|
||||
{ icon: Github, link: "https://github.com/evandrodevbr", rel: "me" },
|
||||
{ icon: Linkedin, link: "https://www.linkedin.com/in/evandro-fonseca-junior-0969aa1b0/", rel: "me" },
|
||||
{ icon: Mail, link: "mailto:[email protected]" }
|
||||
].map((social, i) => (
|
||||
<a key={i} href={social.link} className="p-3 rounded-lg border border-slate-800 text-slate-400 hover:text-white hover:border-slate-600 transition-all">
|
||||
<a
|
||||
key={i}
|
||||
href={social.link}
|
||||
rel={social.rel ? `${social.rel} noopener noreferrer` : "noopener noreferrer"}
|
||||
target={social.link.startsWith("mailto:") ? undefined : "_blank"}
|
||||
className="p-3 rounded-lg border border-slate-800 text-slate-400 hover:text-white hover:border-slate-600 transition-all"
|
||||
>
|
||||
<social.icon className="w-5 h-5" />
|
||||
</a>
|
||||
))}
|
||||
@@ -118,13 +124,14 @@ export default function Hero() {
|
||||
fill
|
||||
className="object-cover grayscale hover:grayscale-0 transition-all duration-700 scale-105 hover:scale-100"
|
||||
priority
|
||||
fetchPriority="high"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Floating Stats Badge */}
|
||||
<div className="absolute -bottom-6 -right-6 bg-slate-900 border border-slate-800 p-4 rounded-2xl shadow-2xl z-20 backdrop-blur-xl">
|
||||
<p className="text-xs text-slate-500 uppercase font-bold tracking-tighter">Exp. Level</p>
|
||||
<p className="text-xl font-mono text-blue-400">Senior Dev</p>
|
||||
<p className="text-xl font-mono text-blue-400">Mid-Level Engineer</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
@@ -24,6 +24,23 @@ const CATEGORY_THEMES: Record<string, any> = {
|
||||
desktop: { color: "text-emerald-400", bg: "bg-emerald-500/10", border: "border-emerald-500/20", icon: Terminal },
|
||||
};
|
||||
|
||||
// Funções auxiliares para Schema
|
||||
function getApplicationCategory(category: string): string {
|
||||
const map: Record<string, string> = {
|
||||
"full-stack": "WebApplication",
|
||||
"iot": "DesktopApplication",
|
||||
"api": "WebApplication",
|
||||
"web": "WebApplication",
|
||||
"desktop": "DesktopApplication"
|
||||
};
|
||||
return map[category.toLowerCase()] || "WebApplication";
|
||||
}
|
||||
|
||||
function getOperatingSystem(category: string): string {
|
||||
if (category.toLowerCase() === "desktop") return "Windows, Linux";
|
||||
return "Web Browser";
|
||||
}
|
||||
|
||||
export default function Projects() {
|
||||
const { data, loading, error } = usePortfolioData();
|
||||
|
||||
@@ -31,6 +48,38 @@ export default function Projects() {
|
||||
data?.projects.filter((p) => p.featured) || [],
|
||||
[data]);
|
||||
|
||||
const projectsJsonLd = useMemo(() => {
|
||||
if (!projects || projects.length === 0) return null;
|
||||
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ItemList",
|
||||
"itemListElement": projects.map((project, index) => ({
|
||||
"@type": "ListItem",
|
||||
"position": index + 1,
|
||||
"item": {
|
||||
"@type": "SoftwareApplication",
|
||||
"name": project.title,
|
||||
"description": project.description,
|
||||
"applicationCategory": getApplicationCategory(project.category),
|
||||
"operatingSystem": getOperatingSystem(project.category),
|
||||
"url": project.demoUrl || project.githubUrl || `https://evandro.dev.br/#projects`,
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "0",
|
||||
"priceCurrency": "BRL"
|
||||
},
|
||||
"softwareVersion": "1.0.0",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Evandro Fonseca Junior",
|
||||
"url": "https://evandro.dev.br"
|
||||
}
|
||||
}
|
||||
}))
|
||||
};
|
||||
}, [projects]);
|
||||
|
||||
if (loading) return <div className="py-20 text-center animate-pulse text-slate-500 font-mono">Loading_Assets...</div>;
|
||||
if (error) return <div className="py-20 text-center text-red-500">System_Error: Failed to sync projects.</div>;
|
||||
|
||||
@@ -118,6 +167,14 @@ export default function Projects() {
|
||||
);
|
||||
})}
|
||||
</BentoGrid>
|
||||
|
||||
{/* JSON-LD Schema for Projects */}
|
||||
{projectsJsonLd && (
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(projectsJsonLd) }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1024" height="1024">
|
||||
<defs>
|
||||
<image width="978" height="981" id="img1" href="data:image/png;base64,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 truncated
|
||||
</defs>
|
||||
<style>
|
||||
</style>
|
||||
<use id="Background" href="#img1" x="13" y="21"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 383 KiB |
+133
-28
@@ -1,4 +1,4 @@
|
||||
import type { Metadata } from "next";
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import Script from "next/script";
|
||||
// Importação necessária para corrigir o erro de namespace e tipagem do children
|
||||
@@ -8,27 +8,36 @@ import "./globals.css";
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
adjustFontFallback: true,
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
adjustFontFallback: true,
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Evandro Fonseca Junior - Desenvolvedor Full-Stack",
|
||||
title: "Evandro Fonseca Junior - Engenheiro Full-Stack | Next.js, React, Tauri Specialist",
|
||||
description:
|
||||
"Desenvolvedor Full-Stack especializado em soluções web modernas com Angular, React, Node.js e computação em nuvem. Experiência em energia renovável e IoT.",
|
||||
"Engenheiro Full-Stack especializado em Next.js, React, Angular, Node.js e Tauri. Desenvolvedor de sistemas web escaláveis, aplicações desktop e automação. Experiência em PostgreSQL, MySQL, computação em nuvem e IoT.",
|
||||
keywords: [
|
||||
"desenvolvedor",
|
||||
"full-stack",
|
||||
"angular",
|
||||
"react",
|
||||
"node.js",
|
||||
"typescript",
|
||||
"engenheiro full-stack",
|
||||
"Next.js specialist",
|
||||
"React developer",
|
||||
"Tauri developer",
|
||||
"Angular",
|
||||
"Node.js",
|
||||
"TypeScript",
|
||||
"PostgreSQL",
|
||||
"MySQL",
|
||||
"computação em nuvem",
|
||||
"iot",
|
||||
"energia renovável",
|
||||
"IoT",
|
||||
"automação",
|
||||
"arquitetura de software",
|
||||
"sistemas escaláveis",
|
||||
],
|
||||
authors: [{ name: "Evandro Fonseca Junior" }],
|
||||
creator: "Evandro Fonseca Junior",
|
||||
@@ -38,25 +47,34 @@ export const metadata: Metadata = {
|
||||
address: false,
|
||||
telephone: false,
|
||||
},
|
||||
metadataBase: new URL("https://evandrofonsecajunior.dev"),
|
||||
metadataBase: new URL("https://evandro.dev.br"),
|
||||
alternates: {
|
||||
canonical: "/",
|
||||
},
|
||||
openGraph: {
|
||||
title: "Evandro Fonseca Junior - Desenvolvedor Full-Stack",
|
||||
title: "Evandro Fonseca Junior - Engenheiro Full-Stack | Next.js, React, Tauri Specialist",
|
||||
description:
|
||||
"Desenvolvedor Full-Stack especializado em soluções web modernas com Angular, React, Node.js e computação em nuvem.",
|
||||
url: "https://evandrofonsecajunior.dev",
|
||||
"Engenheiro Full-Stack especializado em Next.js, React, Angular, Node.js e Tauri. Desenvolvedor de sistemas web escaláveis e aplicações desktop.",
|
||||
url: "https://evandro.dev.br",
|
||||
siteName: "Evandro Fonseca Junior",
|
||||
locale: "pt_BR",
|
||||
type: "website",
|
||||
images: [
|
||||
{
|
||||
url: "/opengraph-image",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: "Evandro Fonseca Junior - Engenheiro Full-Stack | Next.js, React, Tauri Specialist",
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "Evandro Fonseca Junior - Desenvolvedor Full-Stack",
|
||||
title: "Evandro Fonseca Junior - Engenheiro Full-Stack | Next.js, React, Tauri Specialist",
|
||||
description:
|
||||
"Desenvolvedor Full-Stack especializado em soluções web modernas com Angular, React, Node.js e computação em nuvem.",
|
||||
"Engenheiro Full-Stack especializado em Next.js, React, Angular, Node.js e Tauri. Desenvolvedor de sistemas web escaláveis e aplicações desktop.",
|
||||
creator: "@evandrodevbr",
|
||||
images: ["/opengraph-image"],
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
@@ -71,12 +89,56 @@ export const metadata: Metadata = {
|
||||
},
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: "#000000",
|
||||
width: "device-width",
|
||||
initialScale: 1,
|
||||
maximumScale: 5,
|
||||
};
|
||||
|
||||
// Interface tipada corretamente
|
||||
interface RootLayoutProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ProfilePage",
|
||||
"mainEntity": {
|
||||
"@type": "Person",
|
||||
"name": "Evandro Fonseca Junior",
|
||||
"alternateName": "Evandro.dev",
|
||||
"jobTitle": "Engenheiro de Software Full-Stack",
|
||||
"url": "https://evandro.dev.br",
|
||||
"sameAs": [
|
||||
"https://github.com/evandrodevbr",
|
||||
"https://www.linkedin.com/in/evandro-fonseca-junior-0969aa1b0/",
|
||||
],
|
||||
"knowsAbout": [
|
||||
"Software Engineering",
|
||||
"Next.js",
|
||||
"React",
|
||||
"Angular",
|
||||
"Node.js",
|
||||
"TypeScript",
|
||||
"Tauri",
|
||||
"System Architecture",
|
||||
"Cloud Computing",
|
||||
"IoT",
|
||||
"Automation",
|
||||
"PostgreSQL",
|
||||
"MySQL",
|
||||
],
|
||||
"worksFor": {
|
||||
"@type": "Organization",
|
||||
"name": "Freelancer / Consultor Independente",
|
||||
},
|
||||
"description":
|
||||
"Engenheiro de software especializado em arquitetura web moderna, automação e sistemas de alta performance. Experiência em Next.js, React, Angular, Node.js e desenvolvimento de aplicações desktop com Tauri.",
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
@@ -98,16 +160,10 @@ export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
|
||||
<link rel="dns-prefetch" href="//www.linkedin.com" />
|
||||
<link rel="dns-prefetch" href="//github.com" />
|
||||
|
||||
{/* Favicon and icons */}
|
||||
<link rel="icon" href="/favicon.ico" sizes="any" />
|
||||
<link rel="apple-touch-icon" href="/favicon.ico" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
{/* SEO and Crawling */}
|
||||
<link rel="canonical" href="https://evandrofonsecajunior.dev" />
|
||||
<link rel="canonical" href="https://evandro.dev.br" />
|
||||
|
||||
{/* Theme color for mobile browsers */}
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="msapplication-TileColor" content="#000000" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta
|
||||
@@ -118,14 +174,14 @@ export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
|
||||
|
||||
{/* Performance hints */}
|
||||
<link rel="preload" href="/edev.jpeg" as="image" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=5"
|
||||
/>
|
||||
</head>
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||
/>
|
||||
{children}
|
||||
<Script
|
||||
src="/analytics/api/script.js"
|
||||
@@ -135,6 +191,55 @@ export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
|
||||
data-replay-block-class="rr-block"
|
||||
data-replay-ignore-class="rr-ignore"
|
||||
strategy="afterInteractive"
|
||||
data-session-replay="true"
|
||||
data-track-errors="true"
|
||||
/>
|
||||
{/* Google Analytics - Interceptor para bypass de adblocker */}
|
||||
<Script
|
||||
id="google-analytics-proxy-interceptor"
|
||||
strategy="beforeInteractive"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
(function() {
|
||||
// Interceptar fetch
|
||||
const originalFetch = window.fetch;
|
||||
window.fetch = function(url, options) {
|
||||
if (typeof url === 'string' && url.includes('google-analytics.com')) {
|
||||
url = url.replace('https://www.google-analytics.com', '/ga');
|
||||
}
|
||||
return originalFetch.call(this, url, options);
|
||||
};
|
||||
|
||||
// Interceptar XMLHttpRequest
|
||||
const originalOpen = XMLHttpRequest.prototype.open;
|
||||
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
|
||||
if (typeof url === 'string' && url.includes('google-analytics.com')) {
|
||||
url = url.replace('https://www.google-analytics.com', '/ga');
|
||||
}
|
||||
return originalOpen.call(this, method, url, ...rest);
|
||||
};
|
||||
})();
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
{/* Google Analytics - Script principal via proxy */}
|
||||
<Script
|
||||
src="/gtm/js/G-QTT9QT0T3S"
|
||||
strategy="afterInteractive"
|
||||
async
|
||||
/>
|
||||
{/* Google Analytics - Inicialização */}
|
||||
<Script
|
||||
id="google-analytics-init"
|
||||
strategy="afterInteractive"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-QTT9QT0T3S');
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { MetadataRoute } from 'next'
|
||||
|
||||
export default function manifest(): MetadataRoute.Manifest {
|
||||
return {
|
||||
name: 'Evandro Fonseca Junior - Portfólio',
|
||||
short_name: 'Evandro.dev',
|
||||
description: 'Portfólio profissional de Evandro Fonseca Junior, Desenvolvedor Full-Stack',
|
||||
start_url: '/',
|
||||
display: 'standalone',
|
||||
background_color: '#000000',
|
||||
theme_color: '#000000',
|
||||
orientation: 'portrait-primary',
|
||||
categories: ['portfolio', 'developer', 'technology'],
|
||||
lang: 'pt-BR',
|
||||
dir: 'ltr',
|
||||
icons: [
|
||||
{
|
||||
src: '/favicon.ico',
|
||||
sizes: 'any',
|
||||
type: 'image/x-icon',
|
||||
},
|
||||
{
|
||||
src: '/icon.svg',
|
||||
sizes: 'any',
|
||||
type: 'image/svg+xml',
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import Link from "next/link";
|
||||
import { Home, ArrowLeft, Code2 } from "lucide-react";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="min-h-screen bg-[#030712] flex items-center justify-center px-6">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<div className="mb-8">
|
||||
<Code2 className="w-24 h-24 text-blue-500 mx-auto mb-4 opacity-50" />
|
||||
<h1 className="text-6xl md:text-8xl font-black text-white mb-4">404</h1>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-400 mb-4">
|
||||
Página não encontrada
|
||||
</h2>
|
||||
<p className="text-slate-500 mb-8">
|
||||
A página que você está procurando não existe ou foi movida.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<Link
|
||||
href="/"
|
||||
className="px-6 py-3 bg-blue-600 hover:bg-blue-500 text-white rounded-lg font-semibold transition-all flex items-center justify-center gap-2"
|
||||
>
|
||||
<Home className="w-5 h-5" />
|
||||
Voltar para Home
|
||||
</Link>
|
||||
<Link
|
||||
href="/#projects"
|
||||
className="px-6 py-3 border border-slate-800 hover:border-slate-600 text-slate-400 hover:text-white rounded-lg font-semibold transition-all flex items-center justify-center gap-2"
|
||||
>
|
||||
<ArrowLeft className="w-5 h-5" />
|
||||
Ver Projetos
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { ImageResponse } from 'next/og'
|
||||
|
||||
export const runtime = 'edge'
|
||||
export const alt = 'Evandro Fonseca Junior - Full Stack Developer'
|
||||
export const size = {
|
||||
width: 1200,
|
||||
height: 630,
|
||||
}
|
||||
export const contentType = 'image/png'
|
||||
|
||||
export default async function Image() {
|
||||
return new ImageResponse(
|
||||
(
|
||||
<div
|
||||
style={{
|
||||
background: '#030712',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: 'white',
|
||||
fontFamily: 'system-ui',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 64,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 20,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
Evandro Fonseca Junior
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 32,
|
||||
color: '#3b82f6',
|
||||
marginTop: 10,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
Desenvolvedor Full-Stack
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
{ ...size }
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { MetadataRoute } from 'next'
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
rules: [
|
||||
{
|
||||
userAgent: '*',
|
||||
allow: '/',
|
||||
disallow: ['/api/', '/_next/', '/admin/'],
|
||||
},
|
||||
],
|
||||
sitemap: 'https://evandro.dev.br/sitemap.xml',
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { MetadataRoute } from 'next'
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
const baseUrl = 'https://evandro.dev.br'
|
||||
const currentDate = new Date().toISOString()
|
||||
|
||||
return [
|
||||
{
|
||||
url: baseUrl,
|
||||
lastModified: currentDate,
|
||||
changeFrequency: 'monthly',
|
||||
priority: 1.0,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/#about`,
|
||||
lastModified: currentDate,
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/#skills`,
|
||||
lastModified: currentDate,
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/#experience`,
|
||||
lastModified: currentDate,
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/#projects`,
|
||||
lastModified: currentDate,
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/#contact`,
|
||||
lastModified: currentDate,
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user