feat(catalogo): link de afiliado por idioma e botão alinhado no rodapé do card
Release / Plano (reaproveitar a imagem?) (push) Successful in 12s
CI / Lint e auditorias (push) Successful in 1m52s
CI / Trivy (dependências e segredos) (push) Successful in 14s
CI / Imagem Docker (linux/arm64) (push) Failing after 1m22s
Release / ci (push) Failing after 3m31s
Release / Publica a imagem (linux/arm64) (push) Skipped
Release / Cria a release no Gitea (push) Skipped
Release / Deploy no Coolify (push) Skipped

O botão do AliExpress passa a ficar no rodapé do card, alinhado entre os cards.
O link usa a coluna Link_<idioma> da planilha (en, es, fr, de, zh-CN) e cai no
Link (Brasil) quando ela está vazia. Colunas de link não viram filtro, e a API
lê A1:AZ1000.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas RayanandClaude Sonnet 5.5 committed 2026-11-02 15:24:23 -03:00
1 parent 5fba78308c
commit 900c61df3d
5 files changed
+39 -14

No files matched your search

+18 -11
View File
@@ -2,6 +2,7 @@
import { ArrowUpRight, Award, Check, CircleHelp } from "lucide-react";
import { usePathname } from "next/navigation";
import { isLinkColumn, linkForLocale } from "@/lib/boardLinks";
const HEADER_MAP_EN = {
"Nome": "Name",
@@ -105,9 +106,13 @@ export default function BoardCard({ board }) {
const isDe = pathname === "/de" || pathname.startsWith("/de/");
const isZh = pathname === "/zh-CN" || pathname.startsWith("/zh-CN/");
const mainFields = ["Nome", "Link", "Imagem", "Loja Oficial"];
const locale = isEn ? "en" : isEs ? "es" : isFr ? "fr" : isDe ? "de" : isZh ? "zh-CN" : "pt";
const link = linkForLocale(board, locale);
const imagem = board.Imagem && link ? board.Imagem.replace(/href="[^"]*"/, `href="${link}"`) : board.Imagem;
const technicalFields = Object.keys(board).filter((key) => !mainFields.includes(key) && board[key]);
const mainFields = ["Nome", "Imagem", "Loja Oficial"];
const technicalFields = Object.keys(board).filter((key) => !isLinkColumn(key) && !mainFields.includes(key) && board[key]);
const valor = (campo) => board[campo]?.toString().toLowerCase().trim();
const recursos = technicalFields.filter((campo) => ["sim", "opcional"].includes(valor(campo)));
@@ -118,7 +123,7 @@ export default function BoardCard({ board }) {
{board.Imagem && (
<div
className="flex shrink-0 justify-center border-b border-line bg-surface-2 p-4 [&_img]:h-44 [&_img]:w-auto [&_img]:max-w-full [&_img]:object-contain"
dangerouslySetInnerHTML={{ __html: board.Imagem }}
dangerouslySetInnerHTML={{ __html: imagem }}
/>
)}
@@ -167,14 +172,16 @@ export default function BoardCard({ board }) {
</div>
)}
{board.Link && (
<a href={board.Link} target="_blank" rel="noopener noreferrer" className="btn btn-primary mt-6 w-full">
{isEn ? "View on AliExpress" : isEs ? "Ver en AliExpress" : isFr ? "Voir sur AliExpress" : isZh ? "在 AliExpress 查看" : isDe ? "Auf AliExpress ansehen" : "Ver no AliExpress"}
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
<span className="sr-only">
{isEn ? " (opens in new tab)" : isEs ? " (abre en una pestaña nueva)" : isFr ? " (ouvre un nouvel onglet)" : isZh ? "(在新标签页打开)" : isDe ? " (öffnet in neuem Tab)" : " (abre em nova aba)"}
</span>
</a>
{link && (
<div className="mt-auto pt-6">
<a href={link} target="_blank" rel="noopener noreferrer" className="btn btn-primary w-full">
{isEn ? "View on AliExpress" : isEs ? "Ver en AliExpress" : isFr ? "Voir sur AliExpress" : isZh ? "在 AliExpress 查看" : isDe ? "Auf AliExpress ansehen" : "Ver no AliExpress"}
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
<span className="sr-only">
{isEn ? " (opens in new tab)" : isEs ? " (abre en una pestaña nueva)" : isFr ? " (ouvre un nouvel onglet)" : isZh ? "(在新标签页打开)" : isDe ? " (öffnet in neuem Tab)" : " (abre em nova aba)"}
</span>
</a>
</div>
)}
</div>
</article>