feat(brand): apply logos, icons and social sharing cards
No files matched your search
|
After Width: | Height: | Size: 2.2 KiB |
@@ -1,185 +1,25 @@
|
|||||||
"use client";
|
import Image from "next/image";
|
||||||
|
|
||||||
import { motion } from "motion/react";
|
|
||||||
import { useReducedMotion } from "@/app/hooks/useReducedMotion";
|
|
||||||
|
|
||||||
interface LogoProps {
|
interface LogoProps {
|
||||||
variant?: "mark" | "wordmark" | "icon";
|
theme?: "dark" | "light";
|
||||||
size?: "sm" | "md" | "lg" | "xl";
|
|
||||||
theme?: "dark" | "light" | "accent";
|
|
||||||
className?: string;
|
className?: string;
|
||||||
showTagline?: boolean;
|
loading?: "eager" | "lazy";
|
||||||
}
|
}
|
||||||
|
|
||||||
const sizeMap = {
|
|
||||||
sm: { width: 32, height: 32 },
|
|
||||||
md: { width: 48, height: 48 },
|
|
||||||
lg: { width: 64, height: 64 },
|
|
||||||
xl: { width: 120, height: 80 },
|
|
||||||
};
|
|
||||||
|
|
||||||
export function Logo({
|
export function Logo({
|
||||||
variant = "mark",
|
|
||||||
size = "md",
|
|
||||||
theme = "dark",
|
theme = "dark",
|
||||||
className = "",
|
className = "w-48",
|
||||||
showTagline = false,
|
loading = "lazy",
|
||||||
}: Readonly<LogoProps>) {
|
}: Readonly<LogoProps>) {
|
||||||
const dimensions = sizeMap[size];
|
|
||||||
const shouldReduceMotion = useReducedMotion();
|
|
||||||
|
|
||||||
const colors = {
|
|
||||||
dark: {
|
|
||||||
primary: "#FFFFFF",
|
|
||||||
slash: "#CCFF00",
|
|
||||||
},
|
|
||||||
light: {
|
|
||||||
primary: "#0A0A0A",
|
|
||||||
slash: "#0A0A0A",
|
|
||||||
},
|
|
||||||
accent: {
|
|
||||||
primary: "#0A0A0A",
|
|
||||||
slash: "rgba(0,0,0,.3)",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const c = colors[theme];
|
|
||||||
|
|
||||||
const hoverMotion = shouldReduceMotion
|
|
||||||
? undefined
|
|
||||||
: {
|
|
||||||
scale: 1.03,
|
|
||||||
rotate: -2,
|
|
||||||
};
|
|
||||||
|
|
||||||
const hoverTransition = {
|
|
||||||
type: "spring" as const,
|
|
||||||
stiffness: 280,
|
|
||||||
damping: 18,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (variant === "icon") {
|
|
||||||
return (
|
|
||||||
<motion.svg
|
|
||||||
width={dimensions.width}
|
|
||||||
height={dimensions.height}
|
|
||||||
viewBox="0 0 64 64"
|
|
||||||
fill="none"
|
|
||||||
className={className}
|
|
||||||
role="img"
|
|
||||||
aria-label="Evandro icon logo"
|
|
||||||
whileHover={hoverMotion}
|
|
||||||
transition={hoverTransition}
|
|
||||||
>
|
|
||||||
<title>Evandro icon logo</title>
|
|
||||||
<rect width="64" height="64" rx="14" fill={c.primary} />
|
|
||||||
<rect
|
|
||||||
x="10"
|
|
||||||
y="10"
|
|
||||||
width="7"
|
|
||||||
height="44"
|
|
||||||
fill={theme === "dark" ? "#0A0A0A" : c.primary}
|
|
||||||
/>
|
|
||||||
<rect
|
|
||||||
x="17"
|
|
||||||
y="10"
|
|
||||||
width="18"
|
|
||||||
height="7"
|
|
||||||
fill={theme === "dark" ? "#0A0A0A" : c.primary}
|
|
||||||
/>
|
|
||||||
<rect
|
|
||||||
x="17"
|
|
||||||
y="28.5"
|
|
||||||
width="14"
|
|
||||||
height="7"
|
|
||||||
fill={theme === "dark" ? "#0A0A0A" : c.primary}
|
|
||||||
/>
|
|
||||||
<rect
|
|
||||||
x="17"
|
|
||||||
y="47"
|
|
||||||
width="18"
|
|
||||||
height="7"
|
|
||||||
fill={theme === "dark" ? "#0A0A0A" : c.primary}
|
|
||||||
/>
|
|
||||||
<polygon points="37,38 41,38 50,26 46,26" fill={c.slash} />
|
|
||||||
<circle
|
|
||||||
cx="52"
|
|
||||||
cy="47"
|
|
||||||
r="5"
|
|
||||||
fill={theme === "dark" ? "#0A0A0A" : c.primary}
|
|
||||||
/>
|
|
||||||
</motion.svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variant === "wordmark") {
|
|
||||||
return (
|
|
||||||
<motion.div
|
|
||||||
className={`flex items-center gap-3 ${className}`}
|
|
||||||
whileHover={hoverMotion}
|
|
||||||
transition={hoverTransition}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
width={dimensions.width}
|
|
||||||
height={dimensions.height}
|
|
||||||
viewBox="0 0 48 32"
|
|
||||||
fill="none"
|
|
||||||
role="img"
|
|
||||||
aria-label="Evandro wordmark logo"
|
|
||||||
>
|
|
||||||
<title>Evandro wordmark logo</title>
|
|
||||||
<rect x="2" y="2" width="7" height="28" fill={c.primary} />
|
|
||||||
<rect x="9" y="2" width="20" height="7" fill={c.primary} />
|
|
||||||
<rect x="9" y="12.5" width="16" height="7" fill={c.primary} />
|
|
||||||
<rect x="9" y="23" width="20" height="7" fill={c.primary} />
|
|
||||||
<polygon points="30,22 34,22 42,10 38,10" fill={c.slash} />
|
|
||||||
<circle cx="44" cy="25" r="4" fill={c.primary} />
|
|
||||||
</svg>
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
className="font-display text-lg font-extrabold tracking-tight"
|
|
||||||
style={{ color: c.primary }}
|
|
||||||
>
|
|
||||||
evandro<span style={{ color: c.slash }}>.</span>dev
|
|
||||||
<span style={{ color: c.slash }}>.</span>br
|
|
||||||
</div>
|
|
||||||
{showTagline && (
|
|
||||||
<div
|
|
||||||
className="mt-1 text-[9px] tracking-widest"
|
|
||||||
style={{
|
|
||||||
color:
|
|
||||||
theme === "dark"
|
|
||||||
? "rgba(255,255,255,.25)"
|
|
||||||
: "rgba(10,10,10,.4)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
DESENVOLVIMENTO DE SOFTWARE
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.svg
|
<Image
|
||||||
width={dimensions.width}
|
src={`/brand/wordmark-${theme}.webp`}
|
||||||
height={dimensions.height}
|
alt="Evandro.dev.br"
|
||||||
viewBox="0 0 120 80"
|
width={1600}
|
||||||
fill="none"
|
height={330}
|
||||||
className={className}
|
sizes="240px"
|
||||||
role="img"
|
loading={loading}
|
||||||
aria-label="Evandro mark logo"
|
className={`block h-auto max-w-full ${className}`}
|
||||||
whileHover={hoverMotion}
|
/>
|
||||||
transition={hoverTransition}
|
|
||||||
>
|
|
||||||
<title>Evandro mark logo</title>
|
|
||||||
<rect x="10" y="8" width="9" height="64" fill={c.primary} />
|
|
||||||
<rect x="19" y="8" width="28" height="9" fill={c.primary} />
|
|
||||||
<rect x="19" y="35.5" width="22" height="9" fill={c.primary} />
|
|
||||||
<rect x="19" y="63" width="28" height="9" fill={c.primary} />
|
|
||||||
<polygon points="50,55 57,55 74,25 67,25" fill={c.slash} />
|
|
||||||
<circle cx="80" cy="63" r="7" fill={c.primary} />
|
|
||||||
</motion.svg>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-labelledby="title"><title>Evandro Fonseca Junior</title><rect width="64" height="64" fill="#0a0a0a"/><path fill="#ccff00" d="M12 12h40v8H21v8h25v8H21v8h31v8H12z"/><path fill="#f4f2ed" d="M22 24h22v8H22z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 288 B |
@@ -10,9 +10,9 @@ import GoogleAnalytics from "./components/GoogleAnalytics";
|
|||||||
import { Header } from "./components/Header";
|
import { Header } from "./components/Header";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
const defaultTitle = "Evandro Fonseca Junior — Engenharia de Software";
|
const defaultTitle = "Sistemas sob medida para empresas | Evandro.dev.br";
|
||||||
const seoDescription =
|
const seoDescription =
|
||||||
"Evandro Fonseca Junior é engenheiro da computação e desenvolvedor de software com atuação em Next.js, TypeScript, Rust, IoT e integrações. Base em Garuva, atendimento a projetos no Norte de Santa Catarina e atuação remota.";
|
"Desenvolvimento de sistemas web, aplicativos e integrações sob medida. Do entendimento do negócio à entrega em produção, com Evandro Fonseca Junior. Base em Santa Catarina e atendimento remoto.";
|
||||||
|
|
||||||
const spaceGrotesk = Space_Grotesk({
|
const spaceGrotesk = Space_Grotesk({
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
@@ -77,7 +77,7 @@ export const metadata: Metadata = {
|
|||||||
url: "/opengraph-image",
|
url: "/opengraph-image",
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 630,
|
height: 630,
|
||||||
alt: "Evandro Fonseca Junior | Engenharia de Software, Next.js, Tauri e Rust",
|
alt: "Evandro.dev.br | Sistemas sob medida para empresas",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -89,7 +89,7 @@ export const metadata: Metadata = {
|
|||||||
images: [
|
images: [
|
||||||
{
|
{
|
||||||
url: "/opengraph-image",
|
url: "/opengraph-image",
|
||||||
alt: "Evandro Fonseca Junior - Engenheiro da Computação e Desenvolvedor de Software",
|
alt: "Evandro.dev.br | Sistemas sob medida para empresas",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -128,6 +128,28 @@ export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
|
|||||||
lang="pt-BR"
|
lang="pt-BR"
|
||||||
className={`${spaceGrotesk.variable} ${geistMono.variable} ${monumentExtended.variable}`}
|
className={`${spaceGrotesk.variable} ${geistMono.variable} ${monumentExtended.variable}`}
|
||||||
>
|
>
|
||||||
|
<head>
|
||||||
|
{/* Set arrival policy before native restoration and client-side layout changes. */}
|
||||||
|
<style id="arrival-scroll-policy">{`html { scroll-behavior: auto !important; }`}</style>
|
||||||
|
<script>{`
|
||||||
|
addEventListener("load", () => {
|
||||||
|
const sheet = document.getElementById("arrival-scroll-policy")?.sheet;
|
||||||
|
if (sheet) sheet.disabled = true;
|
||||||
|
}, { once: true });
|
||||||
|
if (location.pathname === "/") {
|
||||||
|
const navigation = performance.getEntriesByType("navigation")[0];
|
||||||
|
if (navigation?.type !== "back_forward") {
|
||||||
|
history.scrollRestoration = "manual";
|
||||||
|
if (navigation?.type === "reload" && location.hash) {
|
||||||
|
history.replaceState(history.state, "", location.pathname + location.search);
|
||||||
|
}
|
||||||
|
addEventListener("pagehide", () => {
|
||||||
|
history.scrollRestoration = "auto";
|
||||||
|
}, { once: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}</script>
|
||||||
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script type="application/ld+json">{safeJsonLd(jsonLd)}</script>
|
<script type="application/ld+json">{safeJsonLd(jsonLd)}</script>
|
||||||
<a className="skip-link" href="#main-content">
|
<a className="skip-link" href="#main-content">
|
||||||
|
|||||||
@@ -2,28 +2,28 @@ import type { MetadataRoute } from "next";
|
|||||||
|
|
||||||
export default function manifest(): MetadataRoute.Manifest {
|
export default function manifest(): MetadataRoute.Manifest {
|
||||||
return {
|
return {
|
||||||
name: "Evandro Fonseca Junior — Engenheiro da Computação e Desenvolvedor de Software",
|
name: "Evandro.dev.br — Sistemas sob medida para empresas",
|
||||||
short_name: "Evandro.dev",
|
short_name: "Evandro.dev",
|
||||||
description:
|
description:
|
||||||
"Portfólio profissional de Evandro Fonseca Junior, engenheiro da computação e desenvolvedor de software em Garuva, Joinville, Norte de Santa Catarina e Curitiba.",
|
"Desenvolvimento de sistemas web, aplicativos e integrações sob medida. Engenharia de software com Evandro Fonseca Junior, de Santa Catarina para sua empresa.",
|
||||||
start_url: "/",
|
start_url: "/",
|
||||||
display: "standalone",
|
display: "standalone",
|
||||||
background_color: "#000000",
|
background_color: "#000000",
|
||||||
theme_color: "#000000",
|
theme_color: "#000000",
|
||||||
orientation: "portrait-primary",
|
orientation: "portrait-primary",
|
||||||
categories: ["portfolio", "developer", "engineering", "technology"],
|
categories: ["business", "productivity", "technology"],
|
||||||
lang: "pt-BR",
|
lang: "pt-BR",
|
||||||
dir: "ltr",
|
dir: "ltr",
|
||||||
icons: [
|
icons: [
|
||||||
{
|
{
|
||||||
src: "/favicon.ico",
|
src: "/brand/icon-192.png",
|
||||||
sizes: "any",
|
sizes: "192x192",
|
||||||
type: "image/x-icon",
|
type: "image/png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: "/icon.svg",
|
src: "/icon.png",
|
||||||
sizes: "any",
|
sizes: "512x512",
|
||||||
type: "image/svg+xml",
|
type: "image/png",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
import { ImageResponse } from "next/og";
|
import { ImageResponse } from "next/og";
|
||||||
import { OG_CONTENT_TYPE, OG_SIZE, OgCard } from "@/lib/og-card";
|
import { OG_CONTENT_TYPE, OG_SIZE, OgCard } from "@/lib/og-card";
|
||||||
|
|
||||||
export const alt =
|
export const alt = "Evandro.dev.br — Sistemas sob medida para empresas";
|
||||||
"Evandro Fonseca Junior - Engenheiro da Computação e Desenvolvedor de Software";
|
|
||||||
export const size = OG_SIZE;
|
export const size = OG_SIZE;
|
||||||
export const contentType = OG_CONTENT_TYPE;
|
export const contentType = OG_CONTENT_TYPE;
|
||||||
|
|
||||||
export default async function Image() {
|
export default async function Image() {
|
||||||
return new ImageResponse(
|
return new ImageResponse(
|
||||||
<OgCard
|
<OgCard
|
||||||
eyebrow="Portfólio de engenharia de software"
|
eyebrow="Engenharia de software para empresas"
|
||||||
title="Evandro Fonseca Junior"
|
title="Sistemas sob medida."
|
||||||
description="Engenheiro da Computação e Desenvolvedor de Software"
|
description="Da ideia à produção. Sistemas web, aplicativos e integrações com Evandro Fonseca Junior."
|
||||||
/>,
|
/>,
|
||||||
OG_SIZE,
|
OG_SIZE,
|
||||||
);
|
);
|
||||||
|
|||||||
|
After Width: | Height: | Size: 745 KiB |
|
After Width: | Height: | Size: 668 KiB |
|
After Width: | Height: | Size: 821 KiB |
|
After Width: | Height: | Size: 204 KiB |
@@ -1,3 +1,10 @@
|
|||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { join } from "node:path";
|
||||||
|
|
||||||
|
const brandMark = `data:image/png;base64,${readFileSync(
|
||||||
|
join(process.cwd(), "public/brand/mark-dark.png"),
|
||||||
|
).toString("base64")}`;
|
||||||
|
|
||||||
export const OG_SIZE = { width: 1200, height: 630 } as const;
|
export const OG_SIZE = { width: 1200, height: 630 } as const;
|
||||||
export const OG_CONTENT_TYPE = "image/png";
|
export const OG_CONTENT_TYPE = "image/png";
|
||||||
|
|
||||||
@@ -16,6 +23,7 @@ export function OgCard({
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
position: "relative",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
background: "#050505",
|
background: "#050505",
|
||||||
@@ -24,9 +32,17 @@ export function OgCard({
|
|||||||
fontFamily: "Arial, sans-serif",
|
fontFamily: "Arial, sans-serif",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<img
|
||||||
|
src={brandMark}
|
||||||
|
alt="Evandro.dev.br"
|
||||||
|
width={80}
|
||||||
|
height={80}
|
||||||
|
style={{ position: "absolute", top: 48, right: 72 }}
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
paddingRight: 112,
|
||||||
color: "#ccff00",
|
color: "#ccff00",
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
letterSpacing: "0.16em",
|
letterSpacing: "0.16em",
|
||||||
|
|||||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="210 220 830 800"><path fill="#f4f3ef" d="M245 757H321V681H399V606H476V757H399V878H523V757H654V913H594V982H245Z"/><g fill="#d5fa00"><path d="M511 512H667V688H511Z"/><path d="M667 358H821V512H667Z"/><path d="M844 255H947V358H844Z"/><path d="M906 432H1007V533H906Z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 323 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="210 220 830 800"><path fill="#151d1c" d="M245 757H321V681H399V606H476V757H399V878H523V757H654V913H594V982H245Z"/><g fill="#d5fa00"><path d="M511 512H667V688H511Z"/><path d="M667 358H821V512H667Z"/><path d="M844 255H947V358H844Z"/><path d="M906 432H1007V533H906Z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 323 B |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 117 KiB |