feat(v1.4.0): design system semântico, correções de revalidação e melhorias de UX

- Adicionar tokens semânticos de estado (success, warning, info) no globals.css
- Migrar ~60+ componentes de cores hardcoded do Tailwind para tokens semânticos
- Unificar 3 arrays duplicados de cores de categorias em importação única
- Corrigir widgets de boleto/fatura que não atualizavam após pagamento
  (actions de fatura e antecipação não invalidavam cache do dashboard)
- Corrigir scroll em listas Popover+Command (modal prop)
- Adicionar link "detalhes" no card de orçamento para página da categoria
- Adicionar indicadores de tendência coloridos nos cards de métricas
- Estender cores de chart de 6 para 10
- Normalizar dark mode e remover tokens não utilizados

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-02-07 15:14:59 +00:00
parent 390754c0e8
commit f50261208a
60 changed files with 324 additions and 305 deletions

View File

@@ -226,14 +226,14 @@ export function ApiTokensForm({ tokens }: ApiTokensFormProps) {
onClick={handleCopy}
>
{copied ? (
<RiCheckLine className="h-4 w-4 text-green-500" />
<RiCheckLine className="h-4 w-4 text-success" />
) : (
<RiFileCopyLine className="h-4 w-4" />
)}
</Button>
</div>
</div>
<div className="rounded-md bg-amber-50 dark:bg-amber-950/30 p-3 text-sm text-amber-800 dark:text-amber-200">
<div className="rounded-md bg-warning/10 p-3 text-sm text-warning">
<p className="font-medium">Importante:</p>
<ul className="list-disc list-inside mt-1 space-y-1">
<li>Guarde este token em local seguro</li>

View File

@@ -75,7 +75,7 @@ export function CompanionTab({ tokens }: CompanionTabProps) {
<div>
<div className="flex items-center gap-2 mb-1">
<h2 className="text-lg font-bold">OpenSheets Companion</h2>
<span className="inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-700 dark:bg-green-900/30 dark:text-green-400">
<span className="inline-flex items-center gap-1 rounded-full bg-success/10 px-2 py-0.5 text-xs font-medium text-success dark:bg-success/10">
<RiAndroidLine className="h-3 w-3" />
Android
</span>

View File

@@ -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 && (
<p
className="text-xs text-red-600 dark:text-red-400 flex items-center gap-1"
className="text-xs text-destructive flex items-center gap-1"
role="alert"
>
<RiCloseLine className="h-3.5 w-3.5" />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({
<div className="absolute right-3 top-1/2 -translate-y-1/2">
{emailsMatch ? (
<RiCheckLine
className="h-5 w-5 text-green-500"
className="h-5 w-5 text-success"
aria-label="Os e-mails coincidem"
/>
) : (
<RiCloseLine
className="h-5 w-5 text-red-500"
className="h-5 w-5 text-destructive"
aria-label="Os e-mails não coincidem"
/>
)}
@@ -215,7 +215,7 @@ export function UpdateEmailForm({
{emailsMatch === false && (
<p
id="confirm-email-help"
className="text-xs text-red-600 dark:text-red-400 flex items-center gap-1"
className="text-xs text-destructive flex items-center gap-1"
role="alert"
>
<RiCloseLine className="h-3.5 w-3.5" />
@@ -225,7 +225,7 @@ export function UpdateEmailForm({
{emailsMatch === true && (
<p
id="confirm-email-help"
className="text-xs text-green-600 dark:text-green-400 flex items-center gap-1"
className="text-xs text-success flex items-center gap-1"
>
<RiCheckLine className="h-3.5 w-3.5" />
Os e-mails coincidem

View File

@@ -55,9 +55,7 @@ function PasswordRequirement({ met, label }: { met: boolean; label: string }) {
<div
className={cn(
"flex items-center gap-1.5 text-xs transition-colors",
met
? "text-emerald-600 dark:text-emerald-400"
: "text-muted-foreground",
met ? "text-success" : "text-muted-foreground",
)}
>
{met ? (
@@ -133,14 +131,14 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) {
// Se o usuário usa Google OAuth, mostrar aviso
if (isGoogleAuth) {
return (
<div className="rounded-lg border border-amber-200 bg-amber-50 p-4 dark:border-amber-900 dark:bg-amber-950/20">
<div className="rounded-lg border border-warning/30 bg-warning/10 p-4 dark:border-warning/20 dark:bg-warning/10">
<div className="flex gap-3">
<RiAlertLine className="h-5 w-5 text-amber-600 dark:text-amber-500 shrink-0 mt-0.5" />
<RiAlertLine className="h-5 w-5 text-warning shrink-0 mt-0.5" />
<div>
<h3 className="font-medium text-amber-900 dark:text-amber-400">
<h3 className="font-medium text-warning">
Alteração de senha não disponível
</h3>
<p className="mt-1 text-sm text-amber-800 dark:text-amber-500">
<p className="mt-1 text-sm text-warning">
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) {
<div className="absolute right-3 top-1/2 -translate-y-1/2">
{passwordsMatch ? (
<RiCheckLine
className="h-5 w-5 text-green-500"
className="h-5 w-5 text-success"
aria-label="As senhas coincidem"
/>
) : (
<RiCloseLine
className="h-5 w-5 text-red-500"
className="h-5 w-5 text-destructive"
aria-label="As senhas não coincidem"
/>
)}
@@ -328,7 +326,7 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) {
{passwordsMatch === false && (
<p
id="confirm-password-help"
className="text-xs text-red-600 dark:text-red-400 flex items-center gap-1"
className="text-xs text-destructive flex items-center gap-1"
role="alert"
>
<RiCloseLine className="h-3.5 w-3.5" />
@@ -338,7 +336,7 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) {
{passwordsMatch === true && (
<p
id="confirm-password-help"
className="text-xs text-green-600 dark:text-green-400 flex items-center gap-1"
className="text-xs text-success flex items-center gap-1"
>
<RiCheckLine className="h-3.5 w-3.5" />
As senhas coincidem