feat: melhora responsividade e dialogos da interface
This commit is contained in:
@@ -4,7 +4,7 @@ import {
|
||||
RiArchiveLine,
|
||||
RiCheckLine,
|
||||
RiDeleteBin5Line,
|
||||
RiEyeLine,
|
||||
RiFileList2Line,
|
||||
RiInboxUnarchiveLine,
|
||||
RiPencilLine,
|
||||
} from "@remixicon/react";
|
||||
@@ -60,7 +60,7 @@ export function NoteCard({
|
||||
},
|
||||
{
|
||||
label: "detalhes",
|
||||
icon: <RiEyeLine className="size-4" aria-hidden />,
|
||||
icon: <RiFileList2Line className="size-4" aria-hidden />,
|
||||
onClick: onDetails,
|
||||
variant: "default" as const,
|
||||
},
|
||||
@@ -115,7 +115,9 @@ export function NoteCard({
|
||||
</div>
|
||||
<span
|
||||
className={`leading-relaxed ${
|
||||
task.completed ? "text-muted-foreground" : "text-foreground"
|
||||
task.completed
|
||||
? "text-muted-foreground line-through"
|
||||
: "text-foreground"
|
||||
}`}
|
||||
>
|
||||
{task.text}
|
||||
|
||||
@@ -72,11 +72,11 @@ export function NoteDetailsDialog({
|
||||
</DialogHeader>
|
||||
|
||||
{isTask ? (
|
||||
<div className="max-h-[320px] overflow-auto space-y-3">
|
||||
<Card className="max-h-[320px] overflow-auto gap-2 p-2">
|
||||
{sortedTasks.map((task) => (
|
||||
<Card
|
||||
<div
|
||||
key={task.id}
|
||||
className="flex gap-3 p-3 flex-row items-center"
|
||||
className="flex items-center gap-3 px-3 py-1.5 space-y-1 rounded-md hover:bg-muted/50"
|
||||
>
|
||||
<div
|
||||
className={`mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border ${
|
||||
@@ -91,14 +91,16 @@ export function NoteDetailsDialog({
|
||||
</div>
|
||||
<span
|
||||
className={`text-sm ${
|
||||
task.completed ? "text-muted-foreground" : "text-foreground"
|
||||
task.completed
|
||||
? "text-muted-foreground line-through"
|
||||
: "text-foreground"
|
||||
}`}
|
||||
>
|
||||
{task.text}
|
||||
</span>
|
||||
</Card>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="max-h-[320px] overflow-auto whitespace-pre-line wrap-break-word text-sm text-foreground">
|
||||
{note.description}
|
||||
|
||||
@@ -338,7 +338,7 @@ export function NoteDialog({
|
||||
</div>
|
||||
|
||||
{sortedTasks.length > 0 && (
|
||||
<div className="space-y-1 max-h-[240px] overflow-y-auto pr-1">
|
||||
<div className="space-y-1 max-h-[300px] overflow-y-auto pr-1 mt-4 rounded-md p-2 bg-card ">
|
||||
{sortedTasks.map((task) => (
|
||||
<div
|
||||
key={task.id}
|
||||
|
||||
@@ -50,8 +50,11 @@ export function CalculatorDialogContent({
|
||||
return (
|
||||
<DialogContent
|
||||
ref={contentRefCallback}
|
||||
className="p-4 sm:max-w-sm"
|
||||
className="p-5 sm:max-w-sm sm:p-6"
|
||||
onEscapeKeyDown={(e) => e.preventDefault()}
|
||||
onPointerDownOutside={(e) => e.preventDefault()}
|
||||
onFocusOutside={(e) => e.preventDefault()}
|
||||
onInteractOutside={(e) => e.preventDefault()}
|
||||
>
|
||||
<DialogHeader
|
||||
className="cursor-grab select-none space-y-2 active:cursor-grabbing"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { RiCheckLine, RiFileCopyLine } from "@remixicon/react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils/ui";
|
||||
|
||||
export type CalculatorDisplayProps = {
|
||||
history: string | null;
|
||||
@@ -7,6 +8,7 @@ export type CalculatorDisplayProps = {
|
||||
resultText: string | null;
|
||||
copied: boolean;
|
||||
onCopy: () => void;
|
||||
isResultView: boolean;
|
||||
};
|
||||
|
||||
export function CalculatorDisplay({
|
||||
@@ -15,14 +17,27 @@ export function CalculatorDisplay({
|
||||
resultText,
|
||||
copied,
|
||||
onCopy,
|
||||
isResultView,
|
||||
}: CalculatorDisplayProps) {
|
||||
return (
|
||||
<div className="rounded-xl border bg-muted px-4 py-5 text-right">
|
||||
{history && (
|
||||
<div className="text-sm text-muted-foreground">{history}</div>
|
||||
)}
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<div className="text-right text-3xl font-semibold tracking-tight tabular-nums">
|
||||
<div className="flex h-24 flex-col rounded-xl border bg-muted px-4 py-4 text-right">
|
||||
<div className="min-h-5 truncate text-sm text-muted-foreground">
|
||||
{history ?? (
|
||||
<span
|
||||
className="pointer-events-none opacity-0 select-none"
|
||||
aria-hidden
|
||||
>
|
||||
0 + 0
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-auto flex items-end justify-end gap-2">
|
||||
<div
|
||||
className={cn(
|
||||
"truncate text-right font-semibold tracking-tight tabular-nums leading-none transition-all",
|
||||
isResultView ? "text-2xl" : "text-3xl",
|
||||
)}
|
||||
>
|
||||
{expression}
|
||||
</div>
|
||||
{resultText && (
|
||||
|
||||
@@ -64,6 +64,7 @@ export default function Calculator({
|
||||
resultText={resultText}
|
||||
copied={copied}
|
||||
onCopy={copyToClipboard}
|
||||
isResultView={Boolean(history)}
|
||||
/>
|
||||
<CalculatorKeypad buttons={buttons} activeOperator={operator} />
|
||||
{onSelectValue && (
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import {
|
||||
RiChat3Line,
|
||||
RiDeleteBin5Line,
|
||||
RiEyeLine,
|
||||
RiFileList2Line,
|
||||
RiPencilLine,
|
||||
} from "@remixicon/react";
|
||||
import Image from "next/image";
|
||||
@@ -143,7 +143,7 @@ export function CardItem({
|
||||
},
|
||||
{
|
||||
label: "ver fatura",
|
||||
icon: <RiEyeLine className="size-4" aria-hidden />,
|
||||
icon: <RiFileList2Line className="size-4" aria-hidden />,
|
||||
onClick: onInvoice,
|
||||
className: "text-primary",
|
||||
},
|
||||
|
||||
@@ -245,7 +245,7 @@ export function BoletosWidget({ boletos }: BoletosWidgetProps) {
|
||||
}}
|
||||
>
|
||||
<DialogContent
|
||||
className="max-w-md"
|
||||
className="max-w-[calc(100%-2rem)] sm:max-w-md"
|
||||
onEscapeKeyDown={(event) => {
|
||||
if (isProcessing) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -16,8 +16,7 @@ import {
|
||||
sortableKeyboardCoordinates,
|
||||
} from "@dnd-kit/sortable";
|
||||
import {
|
||||
RiArrowDownLine,
|
||||
RiArrowUpLine,
|
||||
RiAddCircleLine,
|
||||
RiCheckLine,
|
||||
RiCloseLine,
|
||||
RiDragMove2Line,
|
||||
@@ -201,11 +200,11 @@ export function DashboardGridEditable({
|
||||
{/* Toolbar */}
|
||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||
{!isEditing ? (
|
||||
<div className="flex min-w-0 flex-col gap-1 sm:flex-row sm:items-center sm:gap-2 px-1">
|
||||
<div className="flex w-full min-w-0 flex-col gap-1 px-1 sm:w-auto sm:flex-row sm:items-center sm:gap-2">
|
||||
<span className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
|
||||
Ações rápidas
|
||||
</span>
|
||||
<div className="-mb-1 flex items-center gap-2 overflow-x-auto pb-1 sm:mb-0 sm:overflow-visible sm:pb-0">
|
||||
<div className="-mb-1 grid w-full grid-cols-3 gap-1 pb-1 sm:mb-0 sm:flex sm:w-auto sm:items-center sm:gap-2 sm:overflow-visible sm:pb-0">
|
||||
<LancamentoDialog
|
||||
mode="create"
|
||||
pagadorOptions={quickActionOptions.pagadorOptions}
|
||||
@@ -218,9 +217,16 @@ export function DashboardGridEditable({
|
||||
defaultPeriod={period}
|
||||
defaultTransactionType="Receita"
|
||||
trigger={
|
||||
<Button size="sm" variant="outline" className="gap-2">
|
||||
<RiArrowUpLine className="size-4 text-success/80" />
|
||||
Nova receita
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="h-12 w-full min-w-0 flex-col justify-center gap-0.5 px-1.5 text-sm whitespace-normal sm:h-8 sm:w-auto sm:flex-row sm:gap-2 sm:px-3 sm:whitespace-nowrap"
|
||||
>
|
||||
<span className="flex items-center gap-0.5">
|
||||
<RiAddCircleLine className="size-3.5 shrink-0 text-success/80" />
|
||||
</span>
|
||||
<span className="sm:hidden">Receita</span>
|
||||
<span className="hidden sm:inline">Nova receita</span>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
@@ -236,18 +242,30 @@ export function DashboardGridEditable({
|
||||
defaultPeriod={period}
|
||||
defaultTransactionType="Despesa"
|
||||
trigger={
|
||||
<Button size="sm" variant="outline" className="gap-2">
|
||||
<RiArrowDownLine className="size-4 text-destructive/80" />
|
||||
Nova despesa
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="h-12 w-full min-w-0 flex-col justify-center gap-0.5 px-1.5 text-sm whitespace-normal sm:h-8 sm:w-auto sm:flex-row sm:gap-2 sm:px-3 sm:whitespace-nowrap"
|
||||
>
|
||||
<span className="flex items-center gap-0.5">
|
||||
<RiAddCircleLine className="size-3.5 shrink-0 text-destructive/80" />
|
||||
</span>
|
||||
<span className="sm:hidden">Despesa</span>
|
||||
<span className="hidden sm:inline">Nova despesa</span>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<NoteDialog
|
||||
mode="create"
|
||||
trigger={
|
||||
<Button size="sm" variant="outline" className="gap-2">
|
||||
<RiTodoLine className="size-4 text-info/80" />
|
||||
Nova anotação
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="h-12 w-full min-w-0 flex-col justify-center gap-0.5 px-1.5 text-sm whitespace-normal sm:h-8 sm:w-auto sm:flex-row sm:gap-2 sm:px-3 sm:whitespace-nowrap"
|
||||
>
|
||||
<RiTodoLine className="size-3.5 shrink-0 text-info/80" />
|
||||
<span className="sm:hidden">Anotação</span>
|
||||
<span className="hidden sm:inline">Nova anotação</span>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
@@ -257,7 +275,7 @@ export function DashboardGridEditable({
|
||||
<div />
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex w-full items-center justify-end gap-2 sm:w-auto">
|
||||
{isEditing ? (
|
||||
<>
|
||||
<Button
|
||||
@@ -281,22 +299,23 @@ export function DashboardGridEditable({
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="grid w-full grid-cols-2 gap-2 sm:flex sm:w-auto">
|
||||
<WidgetSettingsDialog
|
||||
hiddenWidgets={hiddenWidgets}
|
||||
onToggleWidget={handleToggleWidget}
|
||||
onReset={handleReset}
|
||||
triggerClassName="w-full sm:w-auto"
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleStartEditing}
|
||||
className="gap-2"
|
||||
className="w-full gap-2 sm:w-auto"
|
||||
>
|
||||
<RiDragMove2Line className="size-4" />
|
||||
Reordenar
|
||||
</Button>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -80,7 +80,7 @@ export function InstallmentGroupCard({
|
||||
{group.cartaoLogo && (
|
||||
<img
|
||||
src={`/logos/${group.cartaoLogo}`}
|
||||
alt={group.cartaoName}
|
||||
alt={group.cartaoName ?? "Cartão"}
|
||||
className="h-6 w-auto object-contain rounded"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type {
|
||||
InstallmentAnalysisData,
|
||||
InstallmentGroup,
|
||||
PendingInvoice,
|
||||
} from "@/lib/dashboard/expenses/installment-analysis";
|
||||
|
||||
export type { InstallmentAnalysisData, InstallmentGroup, PendingInvoice };
|
||||
export type { InstallmentAnalysisData, InstallmentGroup };
|
||||
|
||||
@@ -419,7 +419,7 @@ export function InvoicesWidget({ invoices }: InvoicesWidgetProps) {
|
||||
}}
|
||||
>
|
||||
<DialogContent
|
||||
className="max-w-md"
|
||||
className="max-w-[calc(100%-2rem)] sm:max-w-md"
|
||||
onEscapeKeyDown={(event) => {
|
||||
if (modalState === "processing") {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { RiEyeLine, RiPencilLine, RiTodoLine } from "@remixicon/react";
|
||||
import { RiFileList2Line, RiPencilLine, RiTodoLine } from "@remixicon/react";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { NoteDetailsDialog } from "@/components/anotacoes/note-details-dialog";
|
||||
import { NoteDialog } from "@/components/anotacoes/note-dialog";
|
||||
@@ -100,13 +100,10 @@ export function NotesWidget({ notes }: NotesWidgetProps) {
|
||||
{buildDisplayTitle(note.title)}
|
||||
</p>
|
||||
<div className="mt-1 flex items-center gap-2">
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="h-5 px-1.5 text-[10px]"
|
||||
>
|
||||
<Badge variant="outline" className="h-5 px-1.5 text-[10px]">
|
||||
{getTasksSummary(note)}
|
||||
</Badge>
|
||||
<p className="truncate text-xs text-muted-foreground">
|
||||
<p className="truncate text-[11px] text-muted-foreground">
|
||||
{DATE_FORMATTER.format(new Date(note.createdAt))}
|
||||
</p>
|
||||
</div>
|
||||
@@ -131,7 +128,7 @@ export function NotesWidget({ notes }: NotesWidgetProps) {
|
||||
note.title,
|
||||
)}`}
|
||||
>
|
||||
<RiEyeLine className="size-4" />
|
||||
<RiFileList2Line className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -14,24 +14,31 @@ import {
|
||||
} from "@/components/ui/dialog";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { widgetsConfig } from "@/lib/dashboard/widgets/widgets-config";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type WidgetSettingsDialogProps = {
|
||||
hiddenWidgets: string[];
|
||||
onToggleWidget: (widgetId: string) => void;
|
||||
onReset: () => void;
|
||||
triggerClassName?: string;
|
||||
};
|
||||
|
||||
export function WidgetSettingsDialog({
|
||||
hiddenWidgets,
|
||||
onToggleWidget,
|
||||
onReset,
|
||||
triggerClassName,
|
||||
}: WidgetSettingsDialogProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className={cn("gap-2", triggerClassName)}
|
||||
>
|
||||
<RiSettings4Line className="size-4" />
|
||||
Widgets
|
||||
</Button>
|
||||
|
||||
@@ -53,9 +53,9 @@ export function LancamentoDetailsDialog({
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="p-0 sm:max-w-xl">
|
||||
<div className="gap-2 space-y-4 py-6">
|
||||
<CardHeader className="flex flex-row items-start border-b">
|
||||
<DialogContent className="p-0 sm:max-w-xl sm:border-0 sm:p-2">
|
||||
<div className="gap-2 space-y-4 py-4">
|
||||
<CardHeader className="flex flex-row items-start border-b sm:border-b-0">
|
||||
<div>
|
||||
<DialogTitle className="group flex items-center gap-2 text-lg">
|
||||
#{lancamento.id}
|
||||
|
||||
@@ -277,7 +277,7 @@ export function LancamentosFilters({
|
||||
|
||||
<div className="flex w-full gap-2 md:w-auto">
|
||||
{exportButton && (
|
||||
<div className="flex-1 md:flex-none [&>*]:w-full [&>*]:md:w-auto">
|
||||
<div className="flex-1 md:flex-none *:w-full *:md:w-auto">
|
||||
{exportButton}
|
||||
</div>
|
||||
)}
|
||||
@@ -291,13 +291,13 @@ export function LancamentosFilters({
|
||||
<DrawerTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="flex-1 md:flex-none text-sm border-dashed relative"
|
||||
className="flex-1 md:flex-none text-sm border-dashed relative bg-transparent"
|
||||
aria-label="Abrir filtros"
|
||||
>
|
||||
<RiFilter3Line className="size-4" />
|
||||
Filtros
|
||||
{hasActiveFilters && (
|
||||
<span className="absolute -top-1 -right-1 size-2 rounded-full bg-primary" />
|
||||
<span className="absolute -top-1 -right-1 size-3 rounded-full bg-primary" />
|
||||
)}
|
||||
</Button>
|
||||
</DrawerTrigger>
|
||||
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
RiChat1Line,
|
||||
RiCheckLine,
|
||||
RiDeleteBin5Line,
|
||||
RiEyeLine,
|
||||
RiFileCopyLine,
|
||||
RiFileList2Line,
|
||||
RiGroupLine,
|
||||
RiHistoryLine,
|
||||
RiMoreFill,
|
||||
@@ -31,8 +31,8 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useMemo, useState } from "react";
|
||||
import { CategoryIcon } from "@/components/categorias/category-icon";
|
||||
import { EmptyState } from "@/components/empty-state";
|
||||
import MoneyValues from "@/components/money-values";
|
||||
import { EmptyState } from "@/components/shared/empty-state";
|
||||
import { TypeBadge } from "@/components/type-badge";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -588,7 +588,7 @@ const buildColumns = ({
|
||||
<DropdownMenuItem
|
||||
onSelect={() => handleViewDetails(row.original)}
|
||||
>
|
||||
<RiEyeLine className="size-4" />
|
||||
<RiFileList2Line className="size-4" />
|
||||
Detalhes
|
||||
</DropdownMenuItem>
|
||||
{row.original.userId === currentUserId && (
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import {
|
||||
RiDeleteBin5Line,
|
||||
RiEyeLine,
|
||||
RiFileList2Line,
|
||||
RiMailSendLine,
|
||||
RiPencilLine,
|
||||
RiVerifiedBadgeFill,
|
||||
@@ -101,7 +101,7 @@ export function PagadorCard({ pagador, onEdit, onRemove }: PagadorCardProps) {
|
||||
href={`/pagadores/${pagador.id}`}
|
||||
className={`text-primary flex items-center gap-1 font-medium transition-opacity hover:opacity-80`}
|
||||
>
|
||||
<RiEyeLine className="size-4" aria-hidden />
|
||||
<RiFileList2Line className="size-4" aria-hidden />
|
||||
detalhes
|
||||
</Link>
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ export function CardCategoryBreakdown({ data }: CardCategoryBreakdownProps) {
|
||||
const _totalAmount = data.reduce((acc, c) => acc + c.amount, 0);
|
||||
|
||||
return (
|
||||
<Card className="h-full">
|
||||
<Card className="h-full overflow-hidden">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="flex items-center gap-1.5 text-base">
|
||||
<RiPieChartLine className="size-4 text-primary" />
|
||||
@@ -44,7 +44,7 @@ export function CardCategoryBreakdown({ data }: CardCategoryBreakdownProps) {
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="pt-0">
|
||||
<CardContent className="overflow-x-hidden pt-0">
|
||||
<div className="flex flex-col">
|
||||
{data.map((category, index) => (
|
||||
<div
|
||||
@@ -80,7 +80,7 @@ export function CardCategoryBreakdown({ data }: CardCategoryBreakdownProps) {
|
||||
</div>
|
||||
|
||||
{/* Progress bar */}
|
||||
<div className="ml-11 mt-1.5">
|
||||
<div className="pl-11 mt-1.5">
|
||||
<Progress className="h-1.5" value={category.percent} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -38,14 +38,14 @@ export function CardTopExpenses({ data }: CardTopExpensesProps) {
|
||||
const maxAmount = Math.max(...data.map((e) => e.amount));
|
||||
|
||||
return (
|
||||
<Card className="h-full">
|
||||
<Card className="h-full overflow-hidden">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="flex items-center gap-1.5 text-base">
|
||||
<RiShoppingBag3Line className="size-4 text-primary" />
|
||||
Top 10 Gastos do Mês
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0">
|
||||
<CardContent className="overflow-x-hidden pt-0">
|
||||
<div className="flex flex-col">
|
||||
{data.map((expense, index) => (
|
||||
<div
|
||||
@@ -66,14 +66,14 @@ export function CardTopExpenses({ data }: CardTopExpensesProps) {
|
||||
<span className="text-sm font-medium truncate block">
|
||||
{expense.name}
|
||||
</span>
|
||||
<div className="flex items-center gap-1 mt-0.5 flex-wrap">
|
||||
<div className="mt-0.5 flex min-w-0 flex-col gap-0.5">
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{expense.date}
|
||||
</span>
|
||||
{expense.category && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="text-xs px-1.5 py-0 h-5"
|
||||
className="h-5 max-w-full px-1.5 py-0 text-xs truncate"
|
||||
>
|
||||
{expense.category}
|
||||
</Badge>
|
||||
@@ -92,7 +92,7 @@ export function CardTopExpenses({ data }: CardTopExpensesProps) {
|
||||
</div>
|
||||
|
||||
{/* Progress bar */}
|
||||
<div className="ml-12 mt-1.5">
|
||||
<div className="pl-12 mt-1.5">
|
||||
<Progress
|
||||
className="h-1.5"
|
||||
value={(expense.amount / maxAmount) * 100}
|
||||
|
||||
@@ -80,14 +80,14 @@ export function CardUsageChart({ data, limit, card }: CardUsageChartProps) {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<CardTitle className="flex items-center gap-1.5 text-base">
|
||||
<RiBarChartBoxLine className="size-4 text-primary" />
|
||||
Histórico de Uso
|
||||
</CardTitle>
|
||||
|
||||
{/* Card logo and name */}
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
{logoPath ? (
|
||||
<Image
|
||||
src={logoPath}
|
||||
@@ -99,13 +99,13 @@ export function CardUsageChart({ data, limit, card }: CardUsageChartProps) {
|
||||
) : (
|
||||
<RiBankCard2Line className="size-5 text-muted-foreground" />
|
||||
)}
|
||||
<span className="text-sm font-medium text-muted-foreground">
|
||||
<span className="max-w-24 truncate text-sm font-medium text-muted-foreground sm:max-w-none">
|
||||
{card.name}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<CardContent className="px-2 sm:px-6">
|
||||
<ChartContainer config={chartConfig} className="h-[280px] w-full">
|
||||
<BarChart
|
||||
data={chartData}
|
||||
|
||||
Reference in New Issue
Block a user