Padroniza copias e badges da interface

This commit is contained in:
Felipe Coutinho
2026-03-14 18:36:02 +00:00
parent 1e8e6e0d3d
commit 62b94e6b1d
45 changed files with 184 additions and 200 deletions

View File

@@ -69,7 +69,7 @@ export function ExpandableWidgetCard({
<div className="pointer-events-none absolute inset-x-0 bottom-0 flex justify-center bg-linear-to-t from-card to-transparent pt-12 pb-6">
<Button
variant="secondary"
className="pointer-events-auto rounded-full text-xs"
className="pointer-events-auto rounded-full text-xs backdrop-blur-sm bg-primary/10"
onClick={() => setIsOpen(true)}
aria-label="Expandir para ver todo o conteúdo"
>

View File

@@ -0,0 +1,88 @@
import { Badge } from "@/shared/components/ui/badge";
import { cn } from "@/shared/utils/ui";
import StatusDot from "./status-dot";
type FinancialKind =
| "receita"
| "despesa"
| "Receita"
| "Despesa"
| "Transferência"
| "transferência"
| "Saldo inicial"
| "Saldo Inicial";
type FinancialKindKey =
| "receita"
| "despesa"
| "transferência"
| "saldo inicial";
type TransactionTypeBadgeProps = {
kind: FinancialKind | string;
className?: string;
};
type BadgeConfig = {
label: string;
className: string;
dotClassName: string;
};
const BADGE_CONFIG: Record<FinancialKindKey, BadgeConfig> = {
receita: {
label: "Receita",
className: "bg-success/10 text-success dark:bg-success/10",
dotClassName: "bg-success/80",
},
despesa: {
label: "Despesa",
className: "bg-destructive/10 text-destructive dark:bg-destructive/10",
dotClassName: "bg-destructive/80",
},
transferência: {
label: "Transferência",
className: "bg-info/10 text-info dark:bg-info/10",
dotClassName: "bg-info/80",
},
"saldo inicial": {
label: "Saldo Inicial",
className: "bg-success/10 text-success dark:bg-success/10",
dotClassName: "bg-success/80",
},
};
function normalizeKind(value: string): FinancialKindKey | null {
const normalizedValue = value.trim().toLowerCase();
return normalizedValue in BADGE_CONFIG
? (normalizedValue as FinancialKindKey)
: null;
}
export function TransactionTypeBadge({
kind,
className,
}: TransactionTypeBadgeProps) {
const normalizedKind = normalizeKind(kind);
const config = normalizedKind ? BADGE_CONFIG[normalizedKind] : null;
const label = config?.label ?? kind;
return (
<Badge
variant="outline"
data-kind={normalizedKind ?? "custom"}
className={cn(
"h-6 gap-1.5 rounded-full border-transparent px-2 py-0 text-xs font-medium shadow-none",
config?.className ??
"bg-muted/30 text-muted-foreground dark:bg-muted/20",
className,
)}
>
<StatusDot
color={config?.dotClassName ?? "bg-muted-foreground/60"}
className="size-1.5"
/>
<span>{label}</span>
</Badge>
);
}

View File

@@ -1,63 +0,0 @@
import { Badge } from "@/shared/components/ui/badge";
import { cn } from "@/shared/utils/ui";
import StatusDot from "./status-dot";
type TypeBadgeType =
| "receita"
| "despesa"
| "Receita"
| "Despesa"
| "Transferência"
| "transferência"
| "Saldo inicial"
| "Saldo Inicial";
interface TypeBadgeProps {
type: TypeBadgeType | string;
className?: string;
}
const TYPE_LABELS: Record<string, string> = {
receita: "Receita",
despesa: "Despesa",
Receita: "Receita",
Despesa: "Despesa",
Transferência: "Transferência",
transferência: "Transferência",
"Saldo inicial": "Saldo Inicial",
"Saldo Inicial": "Saldo Inicial",
};
export function TypeBadge({ type, className }: TypeBadgeProps) {
const normalizedType = type.toLowerCase();
const isReceita = normalizedType === "receita";
const isTransferencia = normalizedType === "transferência";
const isSaldoInicial = normalizedType === "saldo inicial";
const label = TYPE_LABELS[type] || type;
const colorClass = isTransferencia
? "text-info"
: isReceita || isSaldoInicial
? "text-success"
: "text-destructive";
const dotColor = isTransferencia
? "bg-info"
: isReceita || isSaldoInicial
? "bg-success"
: "bg-destructive";
return (
<Badge
variant={"outline"}
className={cn(
"flex items-center gap-1 px-2 text-xs",
colorClass,
className,
)}
>
<StatusDot color={dotColor} />
{label}
</Badge>
);
}

View File

@@ -117,7 +117,7 @@ function CommandGroup({
<CommandPrimitive.Group
data-slot="command-group"
className={cn(
"text-foreground **:[[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:py-1.5 **:[[cmdk-group-heading]]:text-xs **:[[cmdk-group-heading]]:font-medium",
"text-popover-foreground **:[[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:py-1.5 **:[[cmdk-group-heading]]:text-xs **:[[cmdk-group-heading]]:font-medium",
className,
)}
{...props}

View File

@@ -41,7 +41,7 @@ export default function WidgetCard({
<span className="size-4">{icon}</span>
{title}
</CardTitle>
<CardDescription className="text-muted-foreground text-sm lowercase mt-2">
<CardDescription className="text-muted-foreground text-sm lowercase mt-1.5 tracking-tight">
{subtitle}
</CardDescription>
</div>

View File

@@ -42,7 +42,7 @@ export const DEFAULT_CATEGORIES: DefaultCategory[] = [
{ name: "Outras receitas", type: "receita", icon: "RiMore2Line" },
{ name: "Saldo inicial", type: "receita", icon: "RiWallet2Line" },
// Category especial para transferências entre financialAccounts
// Category especial para transferências entre Contas
{
name: "Transferência interna",
type: "receita",