Polish: aria-pressed toggles, deferred row styling, override hint

Fund visibility toggles and the header privacy/theme buttons expose
aria-pressed (FE-16); deferred transactions render struck-through and
muted so the state is visible at a glance (UX-05); the balance-override
input documents its keyboard contract (UX-21). The Budget CSV button
rides in the transactions tab header.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Carlos Escalante
2026-06-10 18:03:55 -06:00
parent 629d1181ae
commit b3a7f5185a
4 changed files with 25 additions and 10 deletions

View File

@@ -189,6 +189,8 @@ export default function YearlyOverview({
onChange={(e) => setEditValue(e.target.value)} onChange={(e) => setEditValue(e.target.value)}
onBlur={handleSave} onBlur={handleSave}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
title="Enter para guardar · vacío para quitar el ajuste · Esc para cancelar"
aria-description="Enter guarda; vacío quita el ajuste"
className="h-7 w-36 text-right font-mono text-sm ml-auto" className="h-7 w-36 text-right font-mono text-sm ml-auto"
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
/> />

View File

@@ -107,6 +107,7 @@ export function getTransactionColumns({
className={cn( className={cn(
'font-mono font-medium', 'font-mono font-medium',
tx.transaction_type !== 'COMPRA' && 'text-primary', tx.transaction_type !== 'COMPRA' && 'text-primary',
tx.deferred_to_next_cycle && 'opacity-50 line-through decoration-muted-foreground/60',
)} )}
> >
{tx.transaction_type === 'COMPRA' ? '-' : '+'} {tx.transaction_type === 'COMPRA' ? '-' : '+'}

View File

@@ -1,5 +1,5 @@
import { useState, useCallback } from 'react'; import { useState, useCallback } from 'react';
import { ChevronLeft, ChevronRight, Calculator } from 'lucide-react'; import { ChevronLeft, ChevronRight, Calculator, Download } from 'lucide-react';
import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner'; import { toast } from 'sonner';
@@ -171,15 +171,26 @@ export default function Budget() {
</TabsContent> </TabsContent>
<TabsContent value="transactions" className="space-y-3 mt-4"> <TabsContent value="transactions" className="space-y-3 mt-4">
<Tabs <div className="flex items-center justify-between gap-2">
value={txSource} <Tabs
onValueChange={(v) => setTxSource(v as typeof txSource)} value={txSource}
> onValueChange={(v) => setTxSource(v as typeof txSource)}
<TabsList> >
<TabsTrigger value="CREDIT_CARD">Tarjeta</TabsTrigger> <TabsList>
<TabsTrigger value="CASH_AND_TRANSFER">Efectivo y Transferencias</TabsTrigger> <TabsTrigger value="CREDIT_CARD">Tarjeta</TabsTrigger>
</TabsList> <TabsTrigger value="CASH_AND_TRANSFER">Efectivo y Transferencias</TabsTrigger>
</Tabs> </TabsList>
</Tabs>
<Button
variant="outline"
size="sm"
onClick={() => window.open('/api/v1/transactions/export', '_blank')}
title="Descargar todas las transacciones como CSV"
>
<Download className="w-4 h-4 mr-2" aria-hidden="true" />
CSV
</Button>
</div>
{txQuery.isError ? ( {txQuery.isError ? (
<ErrorState <ErrorState
message="No se pudieron cargar las transacciones" message="No se pudieron cargar las transacciones"

View File

@@ -523,6 +523,7 @@ export default function Pensions() {
<button <button
key={key} key={key}
onClick={() => toggleFund(key)} onClick={() => toggleFund(key)}
aria-pressed={active}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium transition-all border cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" className="flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium transition-all border cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
style={{ style={{
borderColor: fund.color, borderColor: fund.color,