Add user-controlled animation preferences and reduce motion support

- Persist prefersReducedMotion and animationSpeedMultiplier in user
profile - Provide UI controls to toggle reduce motion and adjust
animation speed globally - Centralize animation preferences via provider
and useAnimationPreferences hook - Apply preferences to charts’
animations (duration, enabled/disabled) - Inline script in layout to
apply preferences early and avoid FOUC - Update CSS to respect user
preference with reduced motion overrides and variable animation speeds
This commit is contained in:
2025-08-11 17:54:53 -04:00
parent 46767ca7e2
commit a270f6c1e5
10 changed files with 1150 additions and 14 deletions
@@ -1,6 +1,7 @@
"use client";
import { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from "recharts";
import { useAnimationPreferences } from "~/components/providers/animation-preferences-provider";
import { getEffectiveInvoiceStatus } from "~/lib/invoice-status";
import type { StoredInvoiceStatus } from "~/types/invoice";
@@ -51,6 +52,12 @@ export function InvoiceStatusChart({ invoices }: InvoiceStatusChartProps) {
paid: "hsl(142, 76%, 36%)", // green
overdue: "hsl(0, 84%, 60%)", // red
};
// Animation / motion preferences
const { prefersReducedMotion, animationSpeedMultiplier } =
useAnimationPreferences();
const pieAnimationDuration = Math.round(
600 / (animationSpeedMultiplier || 1),
);
const formatCurrency = (value: number) => {
return new Intl.NumberFormat("en-US", {
@@ -113,6 +120,9 @@ export function InvoiceStatusChart({ invoices }: InvoiceStatusChartProps) {
outerRadius={80}
stroke="none"
dataKey="count"
isAnimationActive={!prefersReducedMotion}
animationDuration={pieAnimationDuration}
animationEasing="ease-out"
>
{chartData.map((entry, index) => (
<Cell