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),
}));
// Light pastel colors for different statuses
// Use theme-aware colors
const COLORS = {
draft: "hsl(220 9% 46%)", // muted gray
sent: "hsl(210 40% 70%)", // light blue
paid: "hsl(142 76% 85%)", // light green
overdue: "hsl(0 84% 85%)", // light red
draft: "hsl(var(--muted-foreground))",
sent: "oklch(var(--chart-1))",
paid: "oklch(var(--chart-2))",
overdue: "oklch(var(--chart-3))",
};
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">
<p className="font-medium">{label}</p>
<div className="space-y-1 text-sm">
<p style={{ color: "hsl(142 45% 45%)" }}>
<p style={{ color: "oklch(var(--chart-2))" }}>
Paid: {data.paidInvoices}
</p>
<p style={{ color: "hsl(210 40% 50%)" }}>
<p style={{ color: "oklch(var(--chart-1))" }}>
Pending: {data.pendingInvoices}
</p>
<p style={{ color: "hsl(0 65% 55%)" }}>
<p style={{ color: "oklch(var(--chart-3))" }}>
Overdue: {data.overdueInvoices}
</p>
<p className="text-muted-foreground border-t pt-1">
@@ -158,19 +158,19 @@ export function MonthlyMetricsChart({ invoices }: MonthlyMetricsChartProps) {
<Bar
dataKey="paidInvoices"
stackId="a"
fill="hsl(142 76% 85%)"
fill="oklch(var(--chart-2))"
radius={[0, 0, 0, 0]}
/>
<Bar
dataKey="pendingInvoices"
stackId="a"
fill="hsl(210 40% 85%)"
fill="oklch(var(--chart-1))"
radius={[0, 0, 0, 0]}
/>
<Bar
dataKey="overdueInvoices"
stackId="a"
fill="hsl(0 84% 85%)"
fill="oklch(var(--chart-3))"
radius={[2, 2, 0, 0]}
/>
</BarChart>
@@ -182,21 +182,21 @@ export function MonthlyMetricsChart({ invoices }: MonthlyMetricsChartProps) {
<div className="flex items-center space-x-2">
<div
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>
</div>
<div className="flex items-center space-x-2">
<div
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>
</div>
<div className="flex items-center space-x-2">
<div
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>
</div>

View File

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

View File

@@ -213,9 +213,12 @@ async function DashboardStats() {
</p>
</div>
<div
className={`flex items-center space-x-1 text-xs ${
isPositive ? "text-green-600" : "text-red-600"
}`}
className="flex items-center space-x-1 text-xs"
style={{
color: isPositive
? "oklch(var(--chart-2))"
: "oklch(var(--chart-3))",
}}
>
<TrendIcon className="h-3 w-3" />
<span>{stat.change}</span>
@@ -449,16 +452,32 @@ async function RecentActivity() {
)
.slice(0, 5);
const getStatusColor = (status: string) => {
const getStatusStyle = (status: string) => {
switch (status) {
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":
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":
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:
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 className="flex items-center space-x-3">
<Badge className={getStatusColor(invoice.status)}>
<Badge style={getStatusStyle(invoice.status)}>
{invoice.status}
</Badge>
<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
useEffect(() => {

View File

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

View File

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