diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4b772ab..e5b7aff 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,36 @@ Todas as mudanças notáveis deste projeto serão documentadas neste arquivo.
O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/),
e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/).
+## [1.4.0] - 2026-02-07
+
+### Corrigido
+
+- Widgets de boleto/fatura não atualizavam após pagamento: actions de fatura (`updateInvoicePaymentStatusAction`, `updatePaymentDateAction`) e antecipação de parcelas não invalidavam o cache do dashboard
+- Substituídos `revalidatePath()` manuais por `revalidateForEntity()` nas actions de fatura e antecipação
+- Expandido `revalidateConfig.cartoes` para incluir `/contas` e `/lancamentos` (afetados por pagamento de fatura)
+- Scroll não funcionava em listas Popover+Command (estabelecimento, categorias, filtros): adicionado `modal` ao Popover nos 4 componentes afetados
+
+### Adicionado
+
+- Link "detalhes" no card de orçamento para navegar diretamente à página da categoria
+- Indicadores de tendência coloridos nos cards de métricas do dashboard (receitas, despesas, balanço, previsto) com cores semânticas sutis
+- Tokens semânticos de estado no design system: `--success`, `--warning`, `--info` (com foregrounds) para light e dark mode
+- Cores de chart estendidas de 6 para 10 (`--chart-7` a `--chart-10`: teal, violet, cyan, lime)
+- Variantes `success` e `info` no componente Badge
+
+### Alterado
+
+- Migrados ~60+ componentes de cores hardcoded do Tailwind (`green-500`, `red-600`, `amber-500`, `blue-500`, etc.) para tokens semânticos (`success`, `destructive`, `warning`, `info`)
+- Unificados 3 arrays duplicados de cores de categorias (em `category-report-chart.tsx`, `category-history.ts`, `category-history-widget.tsx`) para importação única de `category-colors.ts`
+- Month picker migrado de tokens customizados (`--month-picker`) para tokens padrão (`--card`)
+- Dark mode normalizado: hues consistentes (~70 warm family) em vez de valores dispersos
+- Token `--accent` ajustado para ser visualmente distinto de `--background`
+- Token `--card` corrigido para branco limpo (`oklch(100% 0 0)`)
+
+### Removido
+
+- Tokens não utilizados: `--dark`, `--dark-foreground`, `--month-picker`, `--month-picker-foreground`
+
## [1.3.1] - 2026-02-06
### Adicionado
diff --git a/app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts b/app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts
index fcd4d71..3ad9cab 100644
--- a/app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts
+++ b/app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts
@@ -1,7 +1,6 @@
"use server";
import { and, eq, sql } from "drizzle-orm";
-import { revalidatePath } from "next/cache";
import { z } from "zod";
import {
cartoes,
@@ -11,6 +10,7 @@ import {
pagadores,
} from "@/db/schema";
import { buildInvoicePaymentNote } from "@/lib/accounts/constants";
+import { revalidateForEntity } from "@/lib/actions/helpers";
import { getUser } from "@/lib/auth/server";
import { db } from "@/lib/db";
import {
@@ -206,9 +206,7 @@ export async function updateInvoicePaymentStatusAction(
}
});
- revalidatePath(`/cartoes/${data.cartaoId}/fatura`);
- revalidatePath("/cartoes");
- revalidatePath("/contas");
+ revalidateForEntity("cartoes");
return { success: true, message: successMessageByStatus[data.status] };
} catch (error) {
@@ -275,9 +273,7 @@ export async function updatePaymentDateAction(
.where(eq(lancamentos.id, existingPayment.id));
});
- revalidatePath(`/cartoes/${data.cartaoId}/fatura`);
- revalidatePath("/cartoes");
- revalidatePath("/contas");
+ revalidateForEntity("cartoes");
return { success: true, message: "Data de pagamento atualizada." };
} catch (error) {
diff --git a/app/(dashboard)/lancamentos/anticipation-actions.ts b/app/(dashboard)/lancamentos/anticipation-actions.ts
index 0927545..d2d5c13 100644
--- a/app/(dashboard)/lancamentos/anticipation-actions.ts
+++ b/app/(dashboard)/lancamentos/anticipation-actions.ts
@@ -1,7 +1,6 @@
"use server";
import { and, asc, desc, eq, inArray, isNull, or } from "drizzle-orm";
-import { revalidatePath } from "next/cache";
import { z } from "zod";
import {
antecipacoesParcelas,
@@ -9,7 +8,7 @@ import {
lancamentos,
pagadores,
} from "@/db/schema";
-import { handleActionError } from "@/lib/actions/helpers";
+import { handleActionError, revalidateForEntity } from "@/lib/actions/helpers";
import type { ActionResult } from "@/lib/actions/types";
import { getUser } from "@/lib/auth/server";
import { db } from "@/lib/db";
@@ -263,8 +262,7 @@ export async function createInstallmentAnticipationAction(
.where(inArray(lancamentos.id, data.installmentIds));
});
- revalidatePath("/lancamentos");
- revalidatePath("/dashboard");
+ revalidateForEntity("lancamentos");
return {
success: true,
@@ -427,8 +425,7 @@ export async function cancelInstallmentAnticipationAction(
.where(eq(antecipacoesParcelas.id, data.anticipationId));
});
- revalidatePath("/lancamentos");
- revalidatePath("/dashboard");
+ revalidateForEntity("lancamentos");
return {
success: true,
diff --git a/app/globals.css b/app/globals.css
index 7dd98f8..2595612 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -10,7 +10,7 @@
/* Base surfaces - warm cream with subtle orange undertone */
--background: oklch(96.563% 0.00504 67.275);
--foreground: oklch(18% 0.02 45);
- --card: oklch(100% 0.00011 271.152);
+ --card: oklch(100% 0 0);
--card-foreground: oklch(18% 0.02 45);
--popover: oklch(99.5% 0.004 80);
--popover-foreground: oklch(18% 0.02 45);
@@ -28,9 +28,17 @@
--muted-foreground: oklch(45% 0.015 60);
/* Accent - complementary warm tone */
- --accent: oklch(96.563% 0.00504 67.275);
+ --accent: oklch(94% 0.01 70);
--accent-foreground: oklch(22% 0.025 45);
+ /* Semantic states */
+ --success: oklch(55% 0.17 150);
+ --success-foreground: oklch(98% 0.01 150);
+ --warning: oklch(75.976% 0.16034 71.493);
+ --warning-foreground: oklch(20% 0.04 85);
+ --info: oklch(55% 0.17 250);
+ --info-foreground: oklch(98% 0.01 250);
+
/* Destructive - accessible red */
--destructive: oklch(55% 0.22 27);
--destructive-foreground: oklch(98% 0.005 30);
@@ -40,22 +48,26 @@
--input: oklch(82% 0.012 75);
--ring: oklch(69.18% 0.18855 38.353);
- /* Charts - harmonious, distinct, accessible */
+ /* Charts - 10 harmonious, distinct, accessible colors */
--chart-1: var(--color-emerald-400);
--chart-2: var(--color-orange-400);
--chart-3: var(--color-indigo-400);
--chart-4: var(--color-amber-400);
--chart-5: var(--color-pink-400);
--chart-6: var(--color-stone-400);
+ --chart-7: var(--color-teal-400);
+ --chart-8: var(--color-violet-400);
+ --chart-9: var(--color-cyan-400);
+ --chart-10: var(--color-lime-400);
/* Sidebar - slight elevation from background */
- --sidebar: oklch(100% 0.00011 271.152);
+ --sidebar: oklch(100% 0 0);
--sidebar-foreground: oklch(20% 0.02 45);
--sidebar-primary: oklch(25% 0.025 45);
--sidebar-primary-foreground: oklch(98% 0.008 80);
--sidebar-accent: oklch(96.563% 0.00504 67.275);
--sidebar-accent-foreground: oklch(22% 0.025 45);
- --sidebar-border: oklch(58.814% 0.15852 38.26);
+ --sidebar-border: oklch(69.18% 0.18855 38.353);
--sidebar-ring: oklch(69.18% 0.18855 38.353);
/* Layout */
@@ -79,46 +91,50 @@
--spacing: 0.25rem;
/* Special components */
- --month-picker: oklch(100% 0.00011 271.152);
- --month-picker-foreground: oklch(22% 0.015 45);
- --dark: oklch(22% 0.015 45);
- --dark-foreground: oklch(94% 0.008 80);
--welcome-banner: var(--primary);
- --welcome-banner-foreground: oklch(98% 0.008 80);
+ --welcome-banner-foreground: var(--primary-foreground);
}
.dark {
- /* Base surfaces - true dark with minimal saturation */
- --background: oklch(18.674% 0.00002 271.152);
- --foreground: oklch(92.189% 0.0186 103.516);
- --card: oklch(24.039% 0.00151 16.27);
- --card-foreground: oklch(92.189% 0.0186 103.516);
- --popover: oklch(24.039% 0.00151 16.27);
- --popover-foreground: oklch(92.189% 0.0186 103.516);
+ /* Base surfaces - warm dark with consistent hue family */
+ --background: oklch(18.5% 0.002 70);
+ --foreground: oklch(92% 0.015 80);
+ --card: oklch(24% 0.003 70);
+ --card-foreground: oklch(92% 0.015 80);
+ --popover: oklch(24% 0.003 70);
+ --popover-foreground: oklch(92% 0.015 80);
/* Primary - vibrant terracotta stands out on dark */
--primary: oklch(69.18% 0.18855 38.353);
- --primary-foreground: oklch(20.019% 0.00002 271.152);
+ --primary-foreground: oklch(20% 0.002 70);
/* Secondary - elevated surface */
- --secondary: oklch(22% 0.004 285);
- --secondary-foreground: oklch(92.189% 0.0186 103.516);
+ --secondary: oklch(22% 0.004 70);
+ --secondary-foreground: oklch(92% 0.015 80);
/* Muted - subtle surface variant */
- --muted: oklch(33.674% 0.00531 91.552);
- --muted-foreground: oklch(72.285% 0.00436 286.016);
+ --muted: oklch(33.5% 0.005 70);
+ --muted-foreground: oklch(72% 0.004 70);
/* Accent - subtle highlight */
- --accent: oklch(26.893% 0.00391 84.539);
- --accent-foreground: oklch(92.189% 0.0186 103.516);
+ --accent: oklch(27% 0.004 70);
+ --accent-foreground: oklch(92% 0.015 80);
+
+ /* Semantic states */
+ --success: oklch(65% 0.19 150);
+ --success-foreground: oklch(15% 0.02 150);
+ --warning: oklch(75.976% 0.16034 71.493);
+ --warning-foreground: oklch(15% 0.04 85);
+ --info: oklch(65% 0.17 250);
+ --info-foreground: oklch(15% 0.02 250);
/* Destructive - accessible red for dark */
--destructive: oklch(62% 0.2 28);
--destructive-foreground: oklch(98% 0.005 30);
/* Borders and inputs - visible but subtle */
- --border: oklch(37.332% 0.01493 101.928);
- --input: oklch(32% 0.005 285);
+ --border: oklch(37% 0.01 70);
+ --input: oklch(32% 0.005 70);
--ring: oklch(69.18% 0.18855 38.353);
/* Charts - bright and distinct on dark */
@@ -128,15 +144,19 @@
--chart-4: var(--color-amber-500);
--chart-5: var(--color-pink-500);
--chart-6: var(--color-stone-500);
+ --chart-7: var(--color-teal-500);
+ --chart-8: var(--color-violet-500);
+ --chart-9: var(--color-cyan-500);
+ --chart-10: var(--color-lime-500);
/* Sidebar - slight separation from main */
- --sidebar: oklch(24.039% 0.00151 16.27);
- --sidebar-foreground: oklch(92.189% 0.0186 103.516);
+ --sidebar: oklch(24% 0.003 70);
+ --sidebar-foreground: oklch(92% 0.015 80);
--sidebar-primary: oklch(69.18% 0.18855 38.353);
- --sidebar-primary-foreground: oklch(12.897% 0.00619 87.19);
- --sidebar-accent: oklch(32.242% 0.00447 67.486);
- --sidebar-accent-foreground: oklch(92.189% 0.0186 103.516);
- --sidebar-border: oklch(26% 0.004 285);
+ --sidebar-primary-foreground: oklch(13% 0.006 70);
+ --sidebar-accent: oklch(32% 0.004 70);
+ --sidebar-accent-foreground: oklch(92% 0.015 80);
+ --sidebar-border: oklch(26% 0.004 70);
--sidebar-ring: oklch(69.18% 0.18855 38.353);
/* Layout */
@@ -161,12 +181,8 @@
--spacing: 0.25rem;
/* Special components */
- --month-picker: oklch(24.039% 0.00151 16.27);
- --month-picker-foreground: oklch(92.189% 0.0186 103.516);
- --dark: oklch(92.189% 0.0186 103.516);
- --dark-foreground: oklch(18.711% 0.00427 84.566);
- --welcome-banner: oklch(24.039% 0.00151 16.27);
- --welcome-banner-foreground: oklch(92.189% 0.0186 103.516);
+ --welcome-banner: var(--card);
+ --welcome-banner-foreground: var(--card-foreground);
}
@theme inline {
@@ -184,6 +200,12 @@
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
+ --color-success: var(--success);
+ --color-success-foreground: var(--success-foreground);
+ --color-warning: var(--warning);
+ --color-warning-foreground: var(--warning-foreground);
+ --color-info: var(--info);
+ --color-info-foreground: var(--info-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
@@ -195,6 +217,10 @@
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-chart-6: var(--chart-6);
+ --color-chart-7: var(--chart-7);
+ --color-chart-8: var(--chart-8);
+ --color-chart-9: var(--chart-9);
+ --color-chart-10: var(--chart-10);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
@@ -217,10 +243,6 @@
--shadow-2xl: var(--shadow-2xl);
--tracking-normal: var(--tracking-normal);
--spacing: var(--spacing);
- --color-month-picker: var(--month-picker);
- --color-month-picker-foreground: var(--month-picker-foreground);
- --color-dark: var(--dark);
- --color-dark-foreground: var(--dark-foreground);
--color-welcome-banner: var(--welcome-banner);
--color-welcome-banner-foreground: var(--welcome-banner-foreground);
}
diff --git a/components/ajustes/api-tokens-form.tsx b/components/ajustes/api-tokens-form.tsx
index 01213c1..65b7a97 100644
--- a/components/ajustes/api-tokens-form.tsx
+++ b/components/ajustes/api-tokens-form.tsx
@@ -226,14 +226,14 @@ export function ApiTokensForm({ tokens }: ApiTokensFormProps) {
onClick={handleCopy}
>
{copied ? (
-
+
) : (
)}
-
+
Importante:
Guarde este token em local seguro
diff --git a/components/ajustes/companion-tab.tsx b/components/ajustes/companion-tab.tsx
index 308f300..f697c34 100644
--- a/components/ajustes/companion-tab.tsx
+++ b/components/ajustes/companion-tab.tsx
@@ -75,7 +75,7 @@ export function CompanionTab({ tokens }: CompanionTabProps) {
OpenSheets Companion
-
+
Android
diff --git a/components/ajustes/update-email-form.tsx b/components/ajustes/update-email-form.tsx
index c5d6654..e899de4 100644
--- a/components/ajustes/update-email-form.tsx
+++ b/components/ajustes/update-email-form.tsx
@@ -149,13 +149,13 @@ export function UpdateEmailForm({
aria-invalid={!isEmailDifferent}
className={
!isEmailDifferent
- ? "border-red-500 focus-visible:ring-red-500"
+ ? "border-destructive focus-visible:ring-destructive"
: ""
}
/>
{!isEmailDifferent && newEmail && (
O novo e-mail deve ser
@@ -188,9 +188,9 @@ export function UpdateEmailForm({
aria-invalid={emailsMatch === false}
className={
emailsMatch === false
- ? "border-red-500 focus-visible:ring-red-500 pr-10"
+ ? "border-destructive focus-visible:ring-destructive pr-10"
: emailsMatch === true
- ? "border-green-500 focus-visible:ring-green-500 pr-10"
+ ? "border-success focus-visible:ring-success pr-10"
: ""
}
/>
@@ -199,12 +199,12 @@ export function UpdateEmailForm({
{emailsMatch ? (
) : (
)}
@@ -215,7 +215,7 @@ export function UpdateEmailForm({
{emailsMatch === false && (
@@ -225,7 +225,7 @@ export function UpdateEmailForm({
{emailsMatch === true && (
Os e-mails coincidem
diff --git a/components/ajustes/update-password-form.tsx b/components/ajustes/update-password-form.tsx
index 145c063..840ae41 100644
--- a/components/ajustes/update-password-form.tsx
+++ b/components/ajustes/update-password-form.tsx
@@ -55,9 +55,7 @@ function PasswordRequirement({ met, label }: { met: boolean; label: string }) {
{met ? (
@@ -133,14 +131,14 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) {
// Se o usuário usa Google OAuth, mostrar aviso
if (isGoogleAuth) {
return (
-
+
-
+
-
+
Alteração de senha não disponível
-
+
Você fez login usando sua conta do Google. A senha é gerenciada
diretamente pelo Google e não pode ser alterada aqui. Para
modificar sua senha, acesse as configurações de segurança da sua
@@ -285,9 +283,9 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) {
aria-invalid={passwordsMatch === false}
className={
passwordsMatch === false
- ? "border-red-500 focus-visible:ring-red-500"
+ ? "border-destructive focus-visible:ring-destructive"
: passwordsMatch === true
- ? "border-green-500 focus-visible:ring-green-500"
+ ? "border-success focus-visible:ring-success"
: ""
}
/>
@@ -312,12 +310,12 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) {
{passwordsMatch ? (
) : (
)}
@@ -328,7 +326,7 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) {
{passwordsMatch === false && (
@@ -338,7 +336,7 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) {
{passwordsMatch === true && (
As senhas coincidem
diff --git a/components/anotacoes/note-card.tsx b/components/anotacoes/note-card.tsx
index de632fe..e79dd0e 100644
--- a/components/anotacoes/note-card.tsx
+++ b/components/anotacoes/note-card.tsx
@@ -104,7 +104,7 @@ export function NoteCard({
diff --git a/components/anotacoes/note-details-dialog.tsx b/components/anotacoes/note-details-dialog.tsx
index 51d49e0..b88db5a 100644
--- a/components/anotacoes/note-details-dialog.tsx
+++ b/components/anotacoes/note-details-dialog.tsx
@@ -79,7 +79,7 @@ export function NoteDetailsDialog({
diff --git a/components/anotacoes/note-dialog.tsx b/components/anotacoes/note-dialog.tsx
index 1234cb9..9a17981 100644
--- a/components/anotacoes/note-dialog.tsx
+++ b/components/anotacoes/note-dialog.tsx
@@ -383,7 +383,7 @@ export function NoteDialog({
className="flex items-center gap-3 px-3 py-2 flex-row mt-1"
>
handleToggleTask(task.id)}
disabled={isPending}
diff --git a/components/auth/auth-error-alert.tsx b/components/auth/auth-error-alert.tsx
index 7daa9d0..c4b7062 100644
--- a/components/auth/auth-error-alert.tsx
+++ b/components/auth/auth-error-alert.tsx
@@ -9,7 +9,7 @@ export function AuthErrorAlert({ error }: AuthErrorAlertProps) {
if (!error) return null;
return (
-
+
{error}
diff --git a/components/auth/signup-form.tsx b/components/auth/signup-form.tsx
index 8569ef5..aeb8f35 100644
--- a/components/auth/signup-form.tsx
+++ b/components/auth/signup-form.tsx
@@ -61,9 +61,7 @@ function PasswordRequirement({ met, label }: { met: boolean; label: string }) {
{met ? (
diff --git a/components/calendario/calendar-legend.tsx b/components/calendario/calendar-legend.tsx
index c88701e..9b31829 100644
--- a/components/calendario/calendar-legend.tsx
+++ b/components/calendario/calendar-legend.tsx
@@ -12,7 +12,7 @@ const LEGEND_ITEMS: Array<{
{ type: "lancamento", label: "Lançamentos" },
{ type: "boleto", label: "Boleto com vencimento" },
{ type: "cartao", label: "Vencimento de cartão" },
- { label: "Pagamento fatura", dotColor: "bg-green-600" },
+ { label: "Pagamento fatura", dotColor: "bg-success" },
];
export function CalendarLegend() {
diff --git a/components/calendario/day-cell.tsx b/components/calendario/day-cell.tsx
index c51d042..52a55d3 100644
--- a/components/calendario/day-cell.tsx
+++ b/components/calendario/day-cell.tsx
@@ -18,13 +18,13 @@ export const EVENT_TYPE_STYLES: Record<
> = {
lancamento: {
wrapper:
- "bg-orange-100 text-orange-600 dark:bg-orange-900/10 dark:text-orange-50 border-l-4 border-orange-500",
- dot: "bg-orange-600",
+ "bg-warning/10 text-warning dark:bg-warning/5 dark:text-warning border-l-4 border-warning",
+ dot: "bg-warning",
},
boleto: {
wrapper:
- "bg-blue-100 text-blue-600 dark:bg-blue-900/10 dark:text-blue-50 border-l-4 border-blue-500",
- dot: "bg-blue-600",
+ "bg-info/10 text-info dark:bg-info/5 dark:text-info border-l-4 border-info",
+ dot: "bg-info",
},
cartao: {
wrapper:
@@ -87,8 +87,8 @@ const getEventStyle = (event: CalendarEvent) => {
if (isPagamentoFatura(event)) {
return {
wrapper:
- "bg-green-100 text-green-600 dark:bg-green-900/10 dark:text-green-50 border-l-4 border-green-500",
- dot: "bg-green-600",
+ "bg-success/10 text-success dark:bg-success/5 dark:text-success border-l-4 border-success",
+ dot: "bg-success",
};
}
return eventStyles[event.type];
diff --git a/components/calendario/event-modal.tsx b/components/calendario/event-modal.tsx
index 6d753fd..f913035 100644
--- a/components/calendario/event-modal.tsx
+++ b/components/calendario/event-modal.tsx
@@ -35,7 +35,7 @@ const EventCard = ({
isPagamentoFatura?: boolean;
}) => {
const style = isPagamentoFatura
- ? { dot: "bg-green-600" }
+ ? { dot: "bg-success" }
: EVENT_TYPE_STYLES[type];
return (
@@ -61,7 +61,7 @@ const renderLancamento = (
{event.lancamento.name}
@@ -76,9 +76,7 @@ const renderLancamento = (
{label}
diff --git a/components/categorias/category-detail-header.tsx b/components/categorias/category-detail-header.tsx
index 0b199d4..5fce78d 100644
--- a/components/categorias/category-detail-header.tsx
+++ b/components/categorias/category-detail-header.tsx
@@ -1,4 +1,4 @@
-import { RiArrowDownLine, RiArrowUpLine } from "@remixicon/react";
+import { RiArrowDownSFill, RiArrowUpSFill } from "@remixicon/react";
import type { CategoryType } from "@/lib/categorias/constants";
import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers";
import { cn } from "@/lib/utils/ui";
@@ -40,22 +40,22 @@ export function CategoryDetailHeader({
const variationColor =
category.type === "receita"
? isIncrease
- ? "text-emerald-600"
+ ? "text-success"
: isDecrease
- ? "text-rose-600"
+ ? "text-destructive"
: "text-muted-foreground"
: isIncrease
- ? "text-rose-600"
+ ? "text-destructive"
: isDecrease
- ? "text-emerald-600"
+ ? "text-success"
: "text-muted-foreground";
const variationIcon =
isIncrease || isDecrease ? (
isIncrease ? (
-
+
) : (
-
+
)
) : null;
diff --git a/components/categorias/category-select-items.tsx b/components/categorias/category-select-items.tsx
index 2b72c1b..affc164 100644
--- a/components/categorias/category-select-items.tsx
+++ b/components/categorias/category-select-items.tsx
@@ -7,13 +7,7 @@ export function TypeSelectContent({ label }: { label: string }) {
return (
-
+
{label}
);
diff --git a/components/contas/account-select-items.tsx b/components/contas/account-select-items.tsx
index fb4f659..2237493 100644
--- a/components/contas/account-select-items.tsx
+++ b/components/contas/account-select-items.tsx
@@ -8,11 +8,7 @@ export function StatusSelectContent({ label }: { label: string }) {
return (
{label}
diff --git a/components/contas/account-statement-card.tsx b/components/contas/account-statement-card.tsx
index cf0bea2..e270024 100644
--- a/components/contas/account-statement-card.tsx
+++ b/components/contas/account-statement-card.tsx
@@ -113,7 +113,7 @@ export function AccountStatementCard({
+
{formatCurrency(totalIncomes)}
}
@@ -137,7 +137,7 @@ export function AccountStatementCard({
className={cn(
"font-semibold text-xl",
totalIncomes - totalExpenses >= 0
- ? "text-emerald-600"
+ ? "text-success"
: "text-destructive",
)}
/>
diff --git a/components/dashboard/boletos-widget.tsx b/components/dashboard/boletos-widget.tsx
index e70c1a6..0b205df 100644
--- a/components/dashboard/boletos-widget.tsx
+++ b/components/dashboard/boletos-widget.tsx
@@ -182,8 +182,7 @@ export function BoletosWidget({ boletos }: BoletosWidgetProps) {
{statusLabel}
@@ -203,7 +202,7 @@ export function BoletosWidget({ boletos }: BoletosWidgetProps) {
onClick={() => handleOpenModal(boleto.id)}
>
{boleto.isSettled ? (
-
+
Pago
) : (
@@ -248,7 +247,7 @@ export function BoletosWidget({ boletos }: BoletosWidgetProps) {
>
{modalState === "success" ? (
-
+
diff --git a/components/dashboard/category-history-widget.tsx b/components/dashboard/category-history-widget.tsx
index fe3af94..ac91f6a 100644
--- a/components/dashboard/category-history-widget.tsx
+++ b/components/dashboard/category-history-widget.tsx
@@ -28,6 +28,7 @@ import {
} from "@/components/ui/popover";
import { WidgetEmptyState } from "@/components/widget-empty-state";
import type { CategoryHistoryData } from "@/lib/dashboard/categories/category-history";
+import { CATEGORY_COLORS } from "@/lib/utils/category-colors";
import { getIconComponent } from "@/lib/utils/icons";
type CategoryHistoryWidgetProps = {
@@ -36,14 +37,7 @@ type CategoryHistoryWidgetProps = {
const STORAGE_KEY_SELECTED = "dashboard-category-history-selected";
-// Vibrant colors for categories
-const CHART_COLORS = [
- "#ef4444", // red-500
- "#3b82f6", // blue-500
- "#10b981", // emerald-500
- "#f59e0b", // amber-500
- "#8b5cf6", // violet-500
-];
+const CHART_COLORS = CATEGORY_COLORS;
export function CategoryHistoryWidget({ data }: CategoryHistoryWidgetProps) {
const [selectedCategories, setSelectedCategories] = useState
([]);
@@ -260,7 +254,7 @@ export function CategoryHistoryWidget({ data }: CategoryHistoryWidgetProps) {
)}
{selectedCategories.length < 5 && availableCategories.length > 0 && (
-
+
{IconComponent ? (
-
+
) : (
-
+
)}
{category.name}
@@ -320,9 +314,9 @@ export function CategoryHistoryWidget({ data }: CategoryHistoryWidgetProps) {
className="gap-2"
>
{IconComponent ? (
-
+
) : (
-
+
)}
{category.name}
diff --git a/components/dashboard/expenses-by-category-widget-with-chart.tsx b/components/dashboard/expenses-by-category-widget-with-chart.tsx
index d550c61..669a825 100644
--- a/components/dashboard/expenses-by-category-widget-with-chart.tsx
+++ b/components/dashboard/expenses-by-category-widget-with-chart.tsx
@@ -1,8 +1,8 @@
"use client";
import {
- RiArrowDownLine,
- RiArrowUpLine,
+ RiArrowDownSFill,
+ RiArrowUpSFill,
RiExternalLinkLine,
RiListUnordered,
RiPieChart2Line,
@@ -220,14 +220,14 @@ export function ExpensesByCategoryWidgetWithChart({
- {hasIncrease && }
- {hasDecrease && }
+ {hasIncrease && }
+ {hasDecrease && }
{formatPercentage(category.percentageChange)}
)}
@@ -238,16 +238,12 @@ export function ExpensesByCategoryWidgetWithChart({
{budgetExceeded ? (
diff --git a/components/dashboard/expenses-by-category-widget.tsx b/components/dashboard/expenses-by-category-widget.tsx
index fbef9a3..a555b99 100644
--- a/components/dashboard/expenses-by-category-widget.tsx
+++ b/components/dashboard/expenses-by-category-widget.tsx
@@ -1,6 +1,6 @@
import {
- RiArrowDownLine,
- RiArrowUpLine,
+ RiArrowDownSFill,
+ RiArrowUpSFill,
RiExternalLinkLine,
RiPieChartLine,
RiWallet3Line,
@@ -127,14 +127,14 @@ export function ExpensesByCategoryWidget({
- {hasIncrease && }
- {hasDecrease && }
+ {hasIncrease && }
+ {hasDecrease && }
{formatPercentage(category.percentageChange)}
)}
@@ -145,17 +145,11 @@ export function ExpensesByCategoryWidget({
{budgetExceeded ? (
<>
diff --git a/components/dashboard/income-by-category-widget-with-chart.tsx b/components/dashboard/income-by-category-widget-with-chart.tsx
index 2418d06..2411018 100644
--- a/components/dashboard/income-by-category-widget-with-chart.tsx
+++ b/components/dashboard/income-by-category-widget-with-chart.tsx
@@ -1,8 +1,8 @@
"use client";
import {
- RiArrowDownLine,
- RiArrowUpLine,
+ RiArrowDownSFill,
+ RiArrowUpSFill,
RiExternalLinkLine,
RiListUnordered,
RiPieChart2Line,
@@ -220,14 +220,14 @@ export function IncomeByCategoryWidgetWithChart({
- {hasIncrease && }
- {hasDecrease && }
+ {hasIncrease && }
+ {hasDecrease && }
{formatPercentage(category.percentageChange)}
)}
@@ -240,16 +240,12 @@ export function IncomeByCategoryWidgetWithChart({
{budgetExceeded ? (
diff --git a/components/dashboard/income-by-category-widget.tsx b/components/dashboard/income-by-category-widget.tsx
index 4870877..9d6231d 100644
--- a/components/dashboard/income-by-category-widget.tsx
+++ b/components/dashboard/income-by-category-widget.tsx
@@ -1,6 +1,6 @@
import {
- RiArrowDownLine,
- RiArrowUpLine,
+ RiArrowDownSFill,
+ RiArrowUpSFill,
RiExternalLinkLine,
RiPieChartLine,
RiWallet3Line,
@@ -127,14 +127,14 @@ export function IncomeByCategoryWidget({
- {hasIncrease && }
- {hasDecrease && }
+ {hasIncrease && }
+ {hasDecrease && }
{formatPercentage(category.percentageChange)}
)}
@@ -147,16 +147,12 @@ export function IncomeByCategoryWidget({
{budgetExceeded ? (
diff --git a/components/dashboard/installment-analysis/installment-group-card.tsx b/components/dashboard/installment-analysis/installment-group-card.tsx
index b1522d5..ed31284 100644
--- a/components/dashboard/installment-analysis/installment-group-card.tsx
+++ b/components/dashboard/installment-analysis/installment-group-card.tsx
@@ -176,7 +176,7 @@ export function InstallmentGroupCard({
"flex items-center gap-3 rounded-md border p-2 transition-colors",
isSelected && !isPaid && "border-primary/50 bg-primary/5",
isPaid &&
- "border-green-400 bg-green-50 dark:border-green-900 dark:bg-green-950/30",
+ "border-success/40 bg-success/5 dark:border-success/20 dark:bg-success/5",
)}
>
Parcela {installment.currentInstallment}/
@@ -202,7 +202,7 @@ export function InstallmentGroupCard({
{isPaid && (
Pago
@@ -211,9 +211,7 @@ export function InstallmentGroupCard({
Vencimento: {dueDate}
@@ -224,7 +222,7 @@ export function InstallmentGroupCard({
amount={installment.amount}
className={cn(
"shrink-0 text-sm",
- isPaid && "text-green-700 dark:text-green-400",
+ isPaid && "text-success",
)}
/>
diff --git a/components/dashboard/invoices-widget.tsx b/components/dashboard/invoices-widget.tsx
index 05019d1..fc0c89d 100644
--- a/components/dashboard/invoices-widget.tsx
+++ b/components/dashboard/invoices-widget.tsx
@@ -358,7 +358,7 @@ export function InvoicesWidget({ invoices }: InvoicesWidgetProps) {
{!isPaid ?
{dueInfo.label} : null}
{isPaid && paymentInfo ? (
-
+
{paymentInfo.label}
) : null}
@@ -378,7 +378,7 @@ export function InvoicesWidget({ invoices }: InvoicesWidgetProps) {
className="p-0 h-auto disabled:opacity-100"
>
{isPaid ? (
-
+
Pago
) : (
@@ -421,7 +421,7 @@ export function InvoicesWidget({ invoices }: InvoicesWidgetProps) {
>
{modalState === "success" ? (
-
+
@@ -489,7 +489,7 @@ export function InvoicesWidget({ invoices }: InvoicesWidgetProps) {
) : null}
{selectedInvoice.paymentStatus ===
INVOICE_PAYMENT_STATUS.PAID && selectedPaymentInfo ? (
-
+
{selectedPaymentInfo.label}
) : null}
diff --git a/components/dashboard/payment-status-widget.tsx b/components/dashboard/payment-status-widget.tsx
index 8ef356f..70b6222 100644
--- a/components/dashboard/payment-status-widget.tsx
+++ b/components/dashboard/payment-status-widget.tsx
@@ -47,13 +47,13 @@ function CategorySection({
{/* Status de confirmados e pendentes */}
-
+
confirmados
-
+
pendentes
diff --git a/components/dashboard/purchases-by-category-widget.tsx b/components/dashboard/purchases-by-category-widget.tsx
index d5eed7f..fabaaf0 100644
--- a/components/dashboard/purchases-by-category-widget.tsx
+++ b/components/dashboard/purchases-by-category-widget.tsx
@@ -1,6 +1,6 @@
"use client";
-import { RiArrowDownLine, RiStore3Line } from "@remixicon/react";
+import { RiArrowDownSFill, RiStore3Line } from "@remixicon/react";
import { useEffect, useMemo, useState } from "react";
import { EstabelecimentoLogo } from "@/components/lancamentos/shared/estabelecimento-logo";
import MoneyValues from "@/components/money-values";
@@ -146,7 +146,7 @@ export function PurchasesByCategoryWidget({
{currentTransactions.length === 0 ? (
}
+ icon={
}
title="Nenhuma compra encontrada"
description={
selectedCategory
diff --git a/components/dashboard/section-cards.tsx b/components/dashboard/section-cards.tsx
index 1b42ebc..61bbd00 100644
--- a/components/dashboard/section-cards.tsx
+++ b/components/dashboard/section-cards.tsx
@@ -1,11 +1,12 @@
import {
RiArrowDownLine,
+ RiArrowDownSFill,
RiArrowUpLine,
- RiCurrencyLine,
+ RiArrowUpSFill,
+ RiCashLine,
RiIncreaseDecreaseLine,
RiSubtractLine,
} from "@remixicon/react";
-import { Badge } from "@/components/ui/badge";
import {
Card,
CardAction,
@@ -25,15 +26,30 @@ type Trend = "up" | "down" | "flat";
const TREND_THRESHOLD = 0.005;
const CARDS = [
- { label: "Receitas", key: "receitas", icon: RiArrowUpLine },
- { label: "Despesas", key: "despesas", icon: RiArrowDownLine },
- { label: "Balanço", key: "balanco", icon: RiIncreaseDecreaseLine },
- { label: "Previsto", key: "previsto", icon: RiCurrencyLine },
+ {
+ label: "Receitas",
+ key: "receitas",
+ icon: RiArrowUpLine,
+ invertTrend: false,
+ },
+ {
+ label: "Despesas",
+ key: "despesas",
+ icon: RiArrowDownLine,
+ invertTrend: true,
+ },
+ {
+ label: "Balanço",
+ key: "balanco",
+ icon: RiIncreaseDecreaseLine,
+ invertTrend: false,
+ },
+ { label: "Previsto", key: "previsto", icon: RiCashLine, invertTrend: false },
] as const;
const TREND_ICONS = {
- up: RiArrowUpLine,
- down: RiArrowDownLine,
+ up: RiArrowUpSFill,
+ down: RiArrowDownSFill,
flat: RiSubtractLine,
} as const;
@@ -58,13 +74,22 @@ const getPercentChange = (current: number, previous: number): string => {
: "—";
};
+const getTrendColor = (trend: Trend, invertTrend: boolean): string => {
+ if (trend === "flat") return "";
+ const isPositive = invertTrend ? trend === "down" : trend === "up";
+ return isPositive
+ ? "text-success border-success"
+ : "text-destructive border-destructive";
+};
+
export function SectionCards({ metrics }: SectionCardsProps) {
return (
- {CARDS.map(({ label, key, icon: Icon }) => {
+ {CARDS.map(({ label, key, icon: Icon, invertTrend }) => {
const metric = metrics[key];
const trend = getTrend(metric.current, metric.previous);
const TrendIcon = TREND_ICONS[trend];
+ const trendColor = getTrendColor(trend, invertTrend);
return (
@@ -75,10 +100,10 @@ export function SectionCards({ metrics }: SectionCardsProps) {
-
-
+
+
{getPercentChange(metric.current, metric.previous)}
-
+
diff --git a/components/faturas/invoice-summary-card.tsx b/components/faturas/invoice-summary-card.tsx
index 319d507..ecc603b 100644
--- a/components/faturas/invoice-summary-card.tsx
+++ b/components/faturas/invoice-summary-card.tsx
@@ -93,7 +93,7 @@ const getCardStatusDotColor = (status: string | null) => {
if (!status) return "bg-gray-400";
const normalizedStatus = status.toLowerCase();
if (normalizedStatus === "ativo" || normalizedStatus === "active") {
- return "bg-green-500";
+ return "bg-success";
}
return "bg-gray-400";
};
diff --git a/components/feedback/feedback-dialog.tsx b/components/feedback/feedback-dialog.tsx
index b628fd8..e2610f3 100644
--- a/components/feedback/feedback-dialog.tsx
+++ b/components/feedback/feedback-dialog.tsx
@@ -35,7 +35,7 @@ const feedbackCategories = [
title: "Reportar Bug",
icon: RiBugLine,
description: "Encontrou algo que não está funcionando?",
- color: "text-red-500 dark:text-red-400",
+ color: "text-destructive",
url: GITHUB_ISSUES_URL,
},
{
@@ -43,7 +43,7 @@ const feedbackCategories = [
title: "Sugerir Feature",
icon: RiLightbulbLine,
description: "Tem uma ideia para melhorar o app?",
- color: "text-yellow-500 dark:text-yellow-400",
+ color: "text-warning",
url: `${GITHUB_DISCUSSIONS_BASE}?category=ideias`,
},
{
@@ -51,7 +51,7 @@ const feedbackCategories = [
title: "Dúvidas/Suporte",
icon: RiQuestionLine,
description: "Precisa de ajuda com alguma coisa?",
- color: "text-blue-500 dark:text-blue-400",
+ color: "text-info",
url: `${GITHUB_DISCUSSIONS_BASE}?category=q-a`,
},
{
diff --git a/components/lancamentos/dialogs/anticipate-installments-dialog/anticipate-installments-dialog.tsx b/components/lancamentos/dialogs/anticipate-installments-dialog/anticipate-installments-dialog.tsx
index 96b930e..03d7231 100644
--- a/components/lancamentos/dialogs/anticipate-installments-dialog/anticipate-installments-dialog.tsx
+++ b/components/lancamentos/dialogs/anticipate-installments-dialog/anticipate-installments-dialog.tsx
@@ -365,7 +365,7 @@ export function AnticipateInstallmentsDialog({
{Number(formState.discount) > 0 && (
Desconto
-
+
-{" "}
= {
- Receita: "bg-emerald-600 dark:bg-emerald-400",
- Despesa: "bg-red-600 dark:bg-red-400",
- Transferência: "bg-blue-600 dark:bg-blue-400",
+ Receita: "bg-success",
+ Despesa: "bg-destructive",
+ Transferência: "bg-info",
};
return (
diff --git a/components/lancamentos/shared/anticipation-card.tsx b/components/lancamentos/shared/anticipation-card.tsx
index b915efc..5259db2 100644
--- a/components/lancamentos/shared/anticipation-card.tsx
+++ b/components/lancamentos/shared/anticipation-card.tsx
@@ -92,7 +92,7 @@ export function AnticipationCard({
{Number(anticipation.discount) > 0 && (
Desconto
-
+
-
diff --git a/components/lancamentos/shared/estabelecimento-input.tsx b/components/lancamentos/shared/estabelecimento-input.tsx
index f25cce1..ab8a8bb 100644
--- a/components/lancamentos/shared/estabelecimento-input.tsx
+++ b/components/lancamentos/shared/estabelecimento-input.tsx
@@ -67,7 +67,7 @@ export function EstabelecimentoInput({
}, [estabelecimentos, searchValue]);
return (
-
+
diff --git a/components/lancamentos/shared/installment-timeline.tsx b/components/lancamentos/shared/installment-timeline.tsx
index 4c5b783..54ea01b 100644
--- a/components/lancamentos/shared/installment-timeline.tsx
+++ b/components/lancamentos/shared/installment-timeline.tsx
@@ -30,7 +30,7 @@ export function InstallmentTimeline({
{/* Linha de conexão */}
-
+
@@ -57,7 +57,7 @@ export function InstallmentTimeline({
{/* Ponto 2: Parcela Atual */}
@@ -74,7 +74,7 @@ export function InstallmentTimeline({
{/* Ponto 3: Última Parcela */}
diff --git a/components/lancamentos/table/lancamentos-filters.tsx b/components/lancamentos/table/lancamentos-filters.tsx
index df1cbde..ec26803 100644
--- a/components/lancamentos/table/lancamentos-filters.tsx
+++ b/components/lancamentos/table/lancamentos-filters.tsx
@@ -388,7 +388,11 @@ export function LancamentosFilters({
Categoria
-
+
);
@@ -545,7 +543,7 @@ const buildColumns = ({
{loading ? (
) : (
-
+
)}
{settled ? "Desfazer pagamento" : "Marcar como pago"}
@@ -631,7 +629,7 @@ const buildColumns = ({
{row.original.isAnticipated && (
-
+
Parcela Antecipada
)}
@@ -799,7 +797,7 @@ export function LancamentosTable({
variant="outline"
className="w-full sm:w-auto"
>
-
+
Nova Receita
-
+
Nova Despesa
>
diff --git a/components/month-picker/month-navigation.tsx b/components/month-picker/month-navigation.tsx
index 792621d..0fa3966 100644
--- a/components/month-picker/month-navigation.tsx
+++ b/components/month-picker/month-navigation.tsx
@@ -79,7 +79,7 @@ export default function MonthNavigation() {
};
return (
-
+
{exceeded ? (
-
+
Excedeu em
) : (
-
+
Restam {" "}
disponíveis.
@@ -98,6 +103,14 @@ export function BudgetCard({
>
editar
+ {budget.category && (
+
+
detalhes
+
+ )}
onRemove(budget)}
diff --git a/components/pagadores/details/pagador-info-card.tsx b/components/pagadores/details/pagador-info-card.tsx
index 1d033e5..80080ca 100644
--- a/components/pagadores/details/pagador-info-card.tsx
+++ b/components/pagadores/details/pagador-info-card.tsx
@@ -193,7 +193,7 @@ export function PagadorInfoCard({
>
) : (
-
+
Acesso somente leitura
)}
@@ -247,7 +247,7 @@ export function PagadorInfoCard({
+
Cadastre um e-mail para permitir o envio automático.
}
@@ -397,7 +397,7 @@ export function PagadorInfoCard({
Pagos
-
+
{formatCurrency(summary.boletoStats.paidAmount)}{" "}
({summary.boletoStats.paidCount})
@@ -408,7 +408,7 @@ export function PagadorInfoCard({
Pendentes
-
+
{formatCurrency(summary.boletoStats.pendingAmount)}{" "}
({summary.boletoStats.pendingCount})
diff --git a/components/pagadores/details/pagador-payment-method-cards.tsx b/components/pagadores/details/pagador-payment-method-cards.tsx
index 3733c62..5a19c93 100644
--- a/components/pagadores/details/pagador-payment-method-cards.tsx
+++ b/components/pagadores/details/pagador-payment-method-cards.tsx
@@ -86,7 +86,7 @@ function StatusRow({ label, amount, count, percent, tone }: StatusRowProps) {
amount={amount}
className={cn(
"text-xl font-semibold",
- tone === "success" ? "text-emerald-600" : "text-amber-600",
+ tone === "success" ? "text-success" : "text-warning",
)}
/>
@@ -95,7 +95,7 @@ function StatusRow({ label, amount, count, percent, tone }: StatusRowProps) {
diff --git a/components/pagadores/pagador-card.tsx b/components/pagadores/pagador-card.tsx
index b8bb061..a0b00d0 100644
--- a/components/pagadores/pagador-card.tsx
+++ b/components/pagadores/pagador-card.tsx
@@ -77,7 +77,7 @@ export function PagadorCard({ pagador, onEdit, onRemove }: PagadorCardProps) {
{isReadOnly ? (
-
+
Somente leitura
) : null}
diff --git a/components/pagadores/pagador-select-items.tsx b/components/pagadores/pagador-select-items.tsx
index 9daa9b8..43877cd 100644
--- a/components/pagadores/pagador-select-items.tsx
+++ b/components/pagadores/pagador-select-items.tsx
@@ -8,11 +8,7 @@ export function StatusSelectContent({ label }: { label: string }) {
return (
{label}
diff --git a/components/relatorios/cartoes/card-invoice-status.tsx b/components/relatorios/cartoes/card-invoice-status.tsx
index e00d1bc..12486f7 100644
--- a/components/relatorios/cartoes/card-invoice-status.tsx
+++ b/components/relatorios/cartoes/card-invoice-status.tsx
@@ -43,11 +43,11 @@ export function CardInvoiceStatus({ data }: CardInvoiceStatusProps) {
const getStatusColor = (status: string | null) => {
switch (status) {
case "pago":
- return "bg-green-500";
+ return "bg-success";
case "pendente":
- return "bg-yellow-500";
+ return "bg-warning";
case "atrasado":
- return "bg-red-500";
+ return "bg-destructive";
default:
return "bg-muted";
}
diff --git a/components/relatorios/cartoes/card-usage-chart.tsx b/components/relatorios/cartoes/card-usage-chart.tsx
index 0a3f629..9a4bb6d 100644
--- a/components/relatorios/cartoes/card-usage-chart.tsx
+++ b/components/relatorios/cartoes/card-usage-chart.tsx
@@ -134,7 +134,7 @@ export function CardUsageChart({ data, limit, card }: CardUsageChartProps) {
label={{
value: "Limite",
position: "right",
- className: "text-xs fill-red-500",
+ className: "text-xs fill-destructive",
}}
/>
)}
diff --git a/components/relatorios/cartoes/cards-overview.tsx b/components/relatorios/cartoes/cards-overview.tsx
index 3a68648..993ee37 100644
--- a/components/relatorios/cartoes/cards-overview.tsx
+++ b/components/relatorios/cartoes/cards-overview.tsx
@@ -58,9 +58,9 @@ export function CardsOverview({ data }: CardsOverviewProps) {
}).format(value);
const getUsageColor = (percent: number) => {
- if (percent < 50) return "bg-green-500";
- if (percent < 80) return "bg-yellow-500";
- return "bg-red-500";
+ if (percent < 50) return "bg-success";
+ if (percent < 80) return "bg-warning";
+ return "bg-destructive";
};
const buildUrl = (cardId: string) => {
diff --git a/components/relatorios/category-cell.tsx b/components/relatorios/category-cell.tsx
index dc9ec96..aefee87 100644
--- a/components/relatorios/category-cell.tsx
+++ b/components/relatorios/category-cell.tsx
@@ -1,6 +1,6 @@
"use client";
-import { RiArrowDownLine, RiArrowUpLine } from "@remixicon/react";
+import { RiArrowDownSFill, RiArrowUpSFill } from "@remixicon/react";
import {
Tooltip,
TooltipContent,
@@ -41,12 +41,12 @@ export function CategoryCell({
- {isIncrease && }
- {isDecrease && }
+ {isIncrease && }
+ {isDecrease && }
{formatPercentageChange(percentageChange)}
)}
@@ -63,8 +63,8 @@ export function CategoryCell({
Diferença:{" "}
diff --git a/components/relatorios/category-report-chart.tsx b/components/relatorios/category-report-chart.tsx
index 7f21d89..db2ba8c 100644
--- a/components/relatorios/category-report-chart.tsx
+++ b/components/relatorios/category-report-chart.tsx
@@ -15,23 +15,13 @@ import { EmptyState } from "@/components/empty-state";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers";
import type { CategoryChartData } from "@/lib/relatorios/fetch-category-chart-data";
+import { CATEGORY_COLORS } from "@/lib/utils/category-colors";
interface CategoryReportChartProps {
data: CategoryChartData;
}
-const CHART_COLORS = [
- "#ef4444", // red-500
- "#3b82f6", // blue-500
- "#10b981", // emerald-500
- "#f59e0b", // amber-500
- "#8b5cf6", // violet-500
- "#ec4899", // pink-500
- "#14b8a6", // teal-500
- "#f97316", // orange-500
- "#06b6d4", // cyan-500
- "#84cc16", // lime-500
-];
+const CHART_COLORS = CATEGORY_COLORS;
const MAX_CATEGORIES_IN_CHART = 15;
diff --git a/components/relatorios/category-report-filters.tsx b/components/relatorios/category-report-filters.tsx
index 1e6ea99..9a84a09 100644
--- a/components/relatorios/category-report-filters.tsx
+++ b/components/relatorios/category-report-filters.tsx
@@ -165,7 +165,7 @@ export function CategoryReportFilters({
{/* Category Multi-Select */}
-
+
diff --git a/components/type-badge.tsx b/components/type-badge.tsx
index e1f5f7f..a2ec198 100644
--- a/components/type-badge.tsx
+++ b/components/type-badge.tsx
@@ -36,16 +36,16 @@ export function TypeBadge({ type, className }: TypeBadgeProps) {
const label = TYPE_LABELS[type] || type;
const colorClass = isTransferencia
- ? "text-blue-700 dark:text-blue-400"
+ ? "text-info"
: isReceita || isSaldoInicial
- ? "text-green-700 dark:text-green-400"
- : "text-red-700 dark:text-red-400";
+ ? "text-success"
+ : "text-destructive";
const dotColor = isTransferencia
- ? "bg-blue-700 dark:bg-blue-400"
+ ? "bg-info"
: isReceita || isSaldoInicial
- ? "bg-green-600 dark:bg-green-400"
- : "bg-red-600 dark:bg-red-400";
+ ? "bg-success"
+ : "bg-destructive";
return (