Files
ESPDocs/components/Footer.jsx
T
Lucas RayanandAntigravity 83c0ba3e74 feat(i18n): routing and localization infrastructure (phase 1)
Implement Phase 1 of i18n spec:
- Configure next-intl with 6 locales (pt, en, es, fr, de, zh-CN) and pathnames
- Move routes to app/[locale] structure with localized layouts and metadata
- Add middleware for root language negotiation (307), legacy redirects (308), and 404 for non-pt book
- Implement language selector dropdown in header with cookie persistence
- Add system typography rules for zh-CN and word-break/hyphenation for de/fr

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 09:31:22 -03:00

181 lines
6.8 KiB
React

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import Logo from "@/components/Logo";
import GiteaMark from "@/components/GiteaMark";
import { ArrowUpRight } from "lucide-react";
import { SITE } from "@/lib/seo";
import { LOCALES, getLocalizedHref } from "@/components/LanguageSelector";
const BASE_COLUMNS = [
{
title: "Explorar",
links: [
{ href: "/series", label: "Séries ESP32" },
{ href: "/comparacao", label: "Comparador" },
{ href: "/catalogo", label: "Catálogo de placas" },
{ href: "/livro", label: "O livro", livroOnly: true },
],
},
{
title: "Ferramentas",
links: [
{ href: "/seletor", label: "Seletor inteligente" },
{ href: "/diagnostico", label: "Diagnóstico" },
{ href: "/componentes", label: "Component Registry" },
{ href: "/frameworks", label: "Frameworks e SDKs" },
],
},
{
title: "Projeto",
links: [
{ href: "/sobre", label: "Sobre o ESPDocs" },
{ href: "/glossario", label: "Glossário" },
{ href: SITE.repositorio, label: "Repositório", external: true },
{ href: `${SITE.repositorio}/issues`, label: "Reportar um problema", external: true },
],
},
];
export default function Footer() {
const pathname = usePathname() || "";
const year = new Date().getFullYear();
const currentLocale =
LOCALES.find((l) => pathname === `/${l.code}` || pathname.startsWith(`/${l.code}/`))?.code || "pt";
const isPt = currentLocale === "pt";
const getLinkHref = (href) => getLocalizedHref(`/${currentLocale}${href}`, currentLocale);
const columns = BASE_COLUMNS.map((col) => ({
...col,
links: col.links.filter((l) => !l.livroOnly || isPt),
}));
return (
<footer className="mt-20 border-t border-line md:mt-28" aria-label="Rodapé do ESPDocs">
<div className="shell py-14 md:py-20">
<div className="grid gap-12 lg:grid-cols-[1.1fr_2fr]">
<div>
<Link href={getLinkHref("/")} className="inline-flex min-h-11 items-center gap-2.5" aria-label="ESPDocs, página inicial">
<Logo className="h-7 w-7" />
<span className="font-display text-2xl font-semibold tracking-[-0.045em] text-ink">ESPDocs</span>
</Link>
<p className="mt-5 max-w-sm text-sm leading-relaxed text-muted">
Documentação independente do ecossistema ESP32, escrita em português brasileiro.
Dados públicos, curadoria editorial e links para as fontes oficiais.
</p>
{isPt && (
<>
<Link
href="/pt/livro"
className="group mt-7 grid grid-cols-[3rem_1fr_auto] items-center gap-3.5 rounded-2xl border border-line bg-surface p-3.5 transition-colors duration-300 hover:border-line-strong"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={SITE.livroCapa}
alt=""
aria-hidden="true"
width={48}
height={72}
className="h-[72px] w-12 rounded-md object-cover shadow-md"
/>
<span className="min-w-0">
<span className="text-xs font-semibold text-accent">Livro novo</span>
<span className="mt-0.5 block font-display text-base font-semibold leading-tight text-ink">Microcontroladores ESP32</span>
<span className="mt-1 block text-xs text-muted">Conectividade, eficiência e desempenho</span>
</span>
<ArrowUpRight className="h-4 w-4 text-faint transition-transform duration-300 group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-accent" aria-hidden="true" />
</Link>
<div className="mt-4 flex flex-wrap gap-x-5 gap-y-2 text-sm">
<a href={SITE.livroAmazon} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center gap-1 text-muted transition-colors hover:text-accent">
Amazon
<ArrowUpRight className="h-3.5 w-3.5" aria-hidden="true" />
</a>
<a href={SITE.livroUiclap} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center gap-1 text-muted transition-colors hover:text-accent">
UICLAP
<ArrowUpRight className="h-3.5 w-3.5" aria-hidden="true" />
</a>
</div>
</>
)}
</div>
<div className="grid grid-cols-2 gap-8 sm:grid-cols-4">
{columns.map((column) => (
<nav key={column.title} aria-label={column.title}>
<h2 className="text-sm font-semibold text-ink">{column.title}</h2>
<ul className="mt-2 space-y-0">
{column.links.map((link) => (
<li key={link.href}>
{link.external ? (
<a
href={link.href}
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center gap-1 text-sm text-muted transition-colors hover:text-accent"
>
{link.label}
<ArrowUpRight className="h-3 w-3" aria-hidden="true" />
</a>
) : (
<Link href={getLinkHref(link.href)} className="inline-flex min-h-11 min-w-11 items-center text-sm text-muted transition-colors hover:text-accent">
{link.label}
</Link>
)}
</li>
))}
</ul>
</nav>
))}
<div>
<h2 className="text-sm font-semibold text-ink">Autor</h2>
<p className="mt-4 text-sm leading-relaxed text-muted">
Lucas Rayan Guerra
<br />
<span className="text-xs text-faint">Ciência Embarcada</span>
</p>
<div className="mt-2 flex flex-wrap gap-x-4 gap-y-1 text-sm">
<a href={SITE.autorUrl} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center text-muted transition-colors hover:text-accent">
Site pessoal
</a>
<a href={SITE.autorLinkedin} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center text-muted transition-colors hover:text-accent">
LinkedIn
</a>
</div>
</div>
</div>
</div>
<div className="mt-12 flex flex-col items-center justify-between gap-4 border-t border-line pt-8 text-xs text-muted sm:flex-row">
<p>© {year} ESPDocs · Conteúdo sob licença MIT. Feito para a comunidade de sistemas embarcados.</p>
<div className="flex items-center gap-6">
<a
href={SITE.repositorio}
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center gap-1.5 transition-colors hover:text-accent"
>
<GiteaMark className="h-4 w-4" aria-hidden="true" />
<span>Gitea</span>
</a>
<span>·</span>
<a
href={SITE.blog}
target="_blank"
rel="noopener noreferrer"
className="inline-flex min-h-11 items-center transition-colors hover:text-accent"
>
Ciência Embarcada
</a>
</div>
</div>
</div>
</footer>
);
}