LP FooterRodapé para landing com grelha, links legais, estado de serviço e moldura Container.
"use client";
import type { ContainerProps } from "@zexon/ui/components/container";
import { Container } from "@zexon/ui/components/container";
import { cn } from "@zexon/ui/lib/utils";
import type * as React from "react";
export interface LPFooterLink {
label: string;
href: string;
}
export interface LPFooterStatus {
/** Texto ao lado do indicador (ex.: “Todos os sistemas operacionais”). */
label: string;
/** `true` = indicador em cor primária; `false` = estado de alerta. */
ok?: boolean;
}
export interface LPFooterProps extends React.ComponentProps<"footer"> {
/** Copyright ou marca (primeira coluna). */
copyright: React.ReactNode;
/** Ligações legais / secundárias (colunas seguintes). */
legalLinks?: LPFooterLink[];
/** Linha de estado de serviço (bolinha + texto). */
status?: LPFooterStatus;
/** Conteúdo à direita na mesma linha do estado (ex.: redes). */
statusTrailing?: React.ReactNode;
/** Conteúdo opcional na última faixa (decoração ou secundário). */
footerBottom?: React.ReactNode;
/** Props adicionais para `Container` (exceto `children`). */
containerProps?: Omit<ContainerProps, "children">;
/** Classe do bloco interior. */
contentClassName?: string;
/** `aria-label` do `<nav>` dos links legais. */
legalNavLabel?: string;
}
const linkClassName =
"cursor-pointer text-sm text-foreground/80 transition-colors hover:text-foreground";
export function LPFooter({
copyright,
legalLinks = [],
status,
statusTrailing,
footerBottom,
containerProps,
contentClassName,
legalNavLabel = "Legal e políticas",
className,
...props
}: LPFooterProps) {
return (
<footer
data-slot="lp-footer"
className={cn("w-full min-w-0 bg-background", className)}
{...props}
>
<Container {...containerProps}>
<div
className={cn(
"min-w-0 divide-y divide-border border-t border-border",
contentClassName,
)}
>
<div className="flex flex-col divide-y divide-border md:flex-row md:divide-x md:divide-y-0">
<div className="flex min-h-12 min-w-0 items-center px-4 py-3 text-sm text-muted-foreground md:flex-1">
{copyright}
</div>
{legalLinks.length > 0 ? (
<nav className="contents" aria-label={legalNavLabel}>
{legalLinks.map((item) => (
<div
key={item.href + item.label}
className="flex min-h-12 min-w-0 items-center px-4 py-3 md:flex-1 md:justify-center"
>
<a href={item.href} className={linkClassName}>
{item.label}
</a>
</div>
))}
</nav>
) : null}
</div>
{status ? (
<div
className={cn(
"flex min-h-12 items-center justify-between gap-4 px-4 py-3",
status.ok !== false ? "text-primary" : "text-destructive",
)}
>
<div className="flex min-w-0 items-center gap-2">
<span
className={cn(
"size-2 shrink-0 rounded-full",
status.ok !== false ? "bg-primary" : "bg-destructive",
)}
aria-hidden
/>
<span className="text-sm font-medium">{status.label}</span>
</div>
{statusTrailing ? (
<div className="flex shrink-0 items-center gap-2">
{statusTrailing}
</div>
) : null}
</div>
) : null}
{footerBottom ? (
<div className="px-4 py-4 text-muted-foreground">{footerBottom}</div>
) : null}
</div>
</Container>
</footer>
);
}