Use theme-aware chart colors and update color variables

This commit is contained in:
2025-07-31 23:10:55 -04:00
parent 8c8f09dab9
commit 43b8fd6c9e
7 changed files with 75 additions and 39 deletions

View File

@@ -43,12 +43,12 @@ export function InvoiceStatusChart({ invoices }: InvoiceStatusChartProps) {
name: item.status.charAt(0).toUpperCase() + item.status.slice(1), name: item.status.charAt(0).toUpperCase() + item.status.slice(1),
})); }));
// Light pastel colors for different statuses // Use theme-aware colors
const COLORS = { const COLORS = {
draft: "hsl(220 9% 46%)", // muted gray draft: "hsl(var(--muted-foreground))",
sent: "hsl(210 40% 70%)", // light blue sent: "oklch(var(--chart-1))",
paid: "hsl(142 76% 85%)", // light green paid: "oklch(var(--chart-2))",
overdue: "hsl(0 84% 85%)", // light red overdue: "oklch(var(--chart-3))",
}; };
const formatCurrency = (value: number) => { const formatCurrency = (value: number) => {

View File

@@ -104,13 +104,13 @@ export function MonthlyMetricsChart({ invoices }: MonthlyMetricsChartProps) {
<div className="bg-card border-border rounded-lg border p-3 shadow-lg"> <div className="bg-card border-border rounded-lg border p-3 shadow-lg">
<p className="font-medium">{label}</p> <p className="font-medium">{label}</p>
<div className="space-y-1 text-sm"> <div className="space-y-1 text-sm">
<p style={{ color: "hsl(142 45% 45%)" }}> <p style={{ color: "oklch(var(--chart-2))" }}>
Paid: {data.paidInvoices} Paid: {data.paidInvoices}
</p> </p>
<p style={{ color: "hsl(210 40% 50%)" }}> <p style={{ color: "oklch(var(--chart-1))" }}>
Pending: {data.pendingInvoices} Pending: {data.pendingInvoices}
</p> </p>
<p style={{ color: "hsl(0 65% 55%)" }}> <p style={{ color: "oklch(var(--chart-3))" }}>
Overdue: {data.overdueInvoices} Overdue: {data.overdueInvoices}
</p> </p>
<p className="text-muted-foreground border-t pt-1"> <p className="text-muted-foreground border-t pt-1">
@@ -158,19 +158,19 @@ export function MonthlyMetricsChart({ invoices }: MonthlyMetricsChartProps) {
<Bar <Bar
dataKey="paidInvoices" dataKey="paidInvoices"
stackId="a" stackId="a"
fill="hsl(142 76% 85%)" fill="oklch(var(--chart-2))"
radius={[0, 0, 0, 0]} radius={[0, 0, 0, 0]}
/> />
<Bar <Bar
dataKey="pendingInvoices" dataKey="pendingInvoices"
stackId="a" stackId="a"
fill="hsl(210 40% 85%)" fill="oklch(var(--chart-1))"
radius={[0, 0, 0, 0]} radius={[0, 0, 0, 0]}
/> />
<Bar <Bar
dataKey="overdueInvoices" dataKey="overdueInvoices"
stackId="a" stackId="a"
fill="hsl(0 84% 85%)" fill="oklch(var(--chart-3))"
radius={[2, 2, 0, 0]} radius={[2, 2, 0, 0]}
/> />
</BarChart> </BarChart>
@@ -182,21 +182,21 @@ export function MonthlyMetricsChart({ invoices }: MonthlyMetricsChartProps) {
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<div <div
className="h-3 w-3 rounded-full" className="h-3 w-3 rounded-full"
style={{ backgroundColor: "hsl(142 76% 85%)" }} style={{ backgroundColor: "oklch(var(--chart-2))" }}
/> />
<span className="text-xs">Paid</span> <span className="text-xs">Paid</span>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<div <div
className="h-3 w-3 rounded-full" className="h-3 w-3 rounded-full"
style={{ backgroundColor: "hsl(210 40% 85%)" }} style={{ backgroundColor: "oklch(var(--chart-1))" }}
/> />
<span className="text-xs">Pending</span> <span className="text-xs">Pending</span>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<div <div
className="h-3 w-3 rounded-full" className="h-3 w-3 rounded-full"
style={{ backgroundColor: "hsl(0 84% 85%)" }} style={{ backgroundColor: "oklch(var(--chart-3))" }}
/> />
<span className="text-xs">Overdue</span> <span className="text-xs">Overdue</span>
</div> </div>

View File

@@ -87,7 +87,7 @@ export function RevenueChart({ invoices }: RevenueChartProps) {
return ( return (
<div className="bg-card border-border rounded-lg border p-3 shadow-lg"> <div className="bg-card border-border rounded-lg border p-3 shadow-lg">
<p className="font-medium">{label}</p> <p className="font-medium">{label}</p>
<p style={{ color: "hsl(210 40% 50%)" }}> <p style={{ color: "oklch(var(--chart-1))" }}>
Revenue: {formatCurrency(data.revenue)} Revenue: {formatCurrency(data.revenue)}
</p> </p>
<p className="text-muted-foreground text-sm"> <p className="text-muted-foreground text-sm">
@@ -122,12 +122,12 @@ export function RevenueChart({ invoices }: RevenueChartProps) {
<linearGradient id="revenueGradient" x1="0" y1="0" x2="0" y2="1"> <linearGradient id="revenueGradient" x1="0" y1="0" x2="0" y2="1">
<stop <stop
offset="5%" offset="5%"
stopColor="hsl(210 40% 70%)" stopColor="oklch(var(--chart-1))"
stopOpacity={0.4} stopOpacity={0.4}
/> />
<stop <stop
offset="95%" offset="95%"
stopColor="hsl(210 40% 70%)" stopColor="oklch(var(--chart-1))"
stopOpacity={0.05} stopOpacity={0.05}
/> />
</linearGradient> </linearGradient>
@@ -148,7 +148,7 @@ export function RevenueChart({ invoices }: RevenueChartProps) {
<Area <Area
type="monotone" type="monotone"
dataKey="revenue" dataKey="revenue"
stroke="hsl(210 40% 60%)" stroke="oklch(var(--chart-1))"
strokeWidth={2} strokeWidth={2}
fill="url(#revenueGradient)" fill="url(#revenueGradient)"
/> />

View File

@@ -213,9 +213,12 @@ async function DashboardStats() {
</p> </p>
</div> </div>
<div <div
className={`flex items-center space-x-1 text-xs ${ className="flex items-center space-x-1 text-xs"
isPositive ? "text-green-600" : "text-red-600" style={{
}`} color: isPositive
? "oklch(var(--chart-2))"
: "oklch(var(--chart-3))",
}}
> >
<TrendIcon className="h-3 w-3" /> <TrendIcon className="h-3 w-3" />
<span>{stat.change}</span> <span>{stat.change}</span>
@@ -449,16 +452,32 @@ async function RecentActivity() {
) )
.slice(0, 5); .slice(0, 5);
const getStatusColor = (status: string) => { const getStatusStyle = (status: string) => {
switch (status) { switch (status) {
case "paid": case "paid":
return "bg-green-50 border-green-200 text-green-700"; return {
backgroundColor: "oklch(var(--chart-2) / 0.1)",
borderColor: "oklch(var(--chart-2) / 0.3)",
color: "oklch(var(--chart-2))",
};
case "sent": case "sent":
return "bg-blue-50 border-blue-200 text-blue-700"; return {
backgroundColor: "oklch(var(--chart-1) / 0.1)",
borderColor: "oklch(var(--chart-1) / 0.3)",
color: "oklch(var(--chart-1))",
};
case "overdue": case "overdue":
return "bg-red-50 border-red-200 text-red-700"; return {
backgroundColor: "oklch(var(--chart-3) / 0.1)",
borderColor: "oklch(var(--chart-3) / 0.3)",
color: "oklch(var(--chart-3))",
};
default: default:
return "bg-gray-50 border-gray-200 text-gray-700"; return {
backgroundColor: "hsl(var(--muted))",
borderColor: "hsl(var(--border))",
color: "hsl(var(--muted-foreground))",
};
} }
}; };
@@ -513,7 +532,7 @@ async function RecentActivity() {
</div> </div>
</div> </div>
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<Badge className={getStatusColor(invoice.status)}> <Badge style={getStatusStyle(invoice.status)}>
{invoice.status} {invoice.status}
</Badge> </Badge>
<span className="font-semibold"> <span className="font-semibold">

View File

@@ -214,7 +214,7 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) {
], ],
})); }));
} }
}, [formData.defaultHourlyRate, formData.items]); }, [formData.defaultHourlyRate]);
// Update default hourly rate when client changes // Update default hourly rate when client changes
useEffect(() => { useEffect(() => {

View File

@@ -19,7 +19,12 @@ export const pool =
ssl: env.NODE_ENV === "production" ? { rejectUnauthorized: false } : false, ssl: env.NODE_ENV === "production" ? { rejectUnauthorized: false } : false,
max: 20, max: 20,
idleTimeoutMillis: 30000, idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000, connectionTimeoutMillis: 10000,
acquireTimeoutMillis: 10000,
createTimeoutMillis: 10000,
destroyTimeoutMillis: 5000,
reapIntervalMillis: 1000,
createRetryIntervalMillis: 200,
}); });
if (env.NODE_ENV !== "production") globalForDb.pool = pool; if (env.NODE_ENV !== "production") globalForDb.pool = pool;

View File

@@ -18,14 +18,18 @@
--accent-foreground: oklch(0.2 0 0); --accent-foreground: oklch(0.2 0 0);
--destructive: oklch(0.58 0.24 28); --destructive: oklch(0.58 0.24 28);
--destructive-foreground: oklch(0.98 0 0); --destructive-foreground: oklch(0.98 0 0);
--success: oklch(0.55 0.15 142);
--success-foreground: oklch(0.98 0 0);
--warning: oklch(0.65 0.15 38);
--warning-foreground: oklch(0.1 0 0);
--border: oklch(0.9 0 0); --border: oklch(0.9 0 0);
--input: oklch(0.9 0 0); --input: oklch(0.9 0 0);
--ring: oklch(0.71 0 0); --ring: oklch(0.71 0 0);
--chart-1: oklch(0.55 0 0); --chart-1: oklch(0.65 0.15 258);
--chart-2: oklch(0.55 0 0); --chart-2: oklch(0.7 0.14 142);
--chart-3: oklch(0.55 0 0); --chart-3: oklch(0.65 0.2 27);
--chart-4: oklch(0.55 0 0); --chart-4: oklch(0.6 0.18 302);
--chart-5: oklch(0.55 0 0); --chart-5: oklch(0.62 0.16 197);
--sidebar: oklch(0.96 0 0); --sidebar: oklch(0.96 0 0);
--sidebar-foreground: oklch(0.15 0 0); --sidebar-foreground: oklch(0.15 0 0);
--sidebar-primary: oklch(0.2 0 0); --sidebar-primary: oklch(0.2 0 0);
@@ -75,14 +79,18 @@
--accent-foreground: oklch(0.98 0 0); --accent-foreground: oklch(0.98 0 0);
--destructive: oklch(0.7 0.19 22); --destructive: oklch(0.7 0.19 22);
--destructive-foreground: oklch(0.22 0 0); --destructive-foreground: oklch(0.22 0 0);
--success: oklch(0.6 0.15 142);
--success-foreground: oklch(0.98 0 0);
--warning: oklch(0.7 0.15 38);
--warning-foreground: oklch(0.1 0 0);
--border: oklch(0.28 0 0); --border: oklch(0.28 0 0);
--input: oklch(0.35 0 0); --input: oklch(0.35 0 0);
--ring: oklch(0.55 0 0); --ring: oklch(0.55 0 0);
--chart-1: oklch(0.55 0 0); --chart-1: oklch(0.7 0.15 258);
--chart-2: oklch(0.55 0 0); --chart-2: oklch(0.75 0.14 142);
--chart-3: oklch(0.55 0 0); --chart-3: oklch(0.7 0.2 27);
--chart-4: oklch(0.55 0 0); --chart-4: oklch(0.65 0.18 302);
--chart-5: oklch(0.55 0 0); --chart-5: oklch(0.67 0.16 197);
--sidebar: oklch(0.08 0 0); --sidebar: oklch(0.08 0 0);
--sidebar-foreground: oklch(0.98 0 0); --sidebar-foreground: oklch(0.98 0 0);
--sidebar-primary: oklch(0.98 0 0); --sidebar-primary: oklch(0.98 0 0);
@@ -131,6 +139,10 @@
--color-accent-foreground: var(--accent-foreground); --color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive); --color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground); --color-destructive-foreground: var(--destructive-foreground);
--color-success: var(--success);
--color-success-foreground: var(--success-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
--color-border: var(--border); --color-border: var(--border);
--color-input: var(--input); --color-input: var(--input);
--color-ring: var(--ring); --color-ring: var(--ring);