mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 22:32:04 +00:00
perf(charts): wire chart-skeleton loading state across dynamic imports
This commit is contained in:
1 parent
4c6d877921
commit
d286220bed
8 files changed
+76
-9
No files matched your search
@@ -0,0 +1,60 @@
|
||||
"use client";
|
||||
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/**
|
||||
* v1.4.28 R3d (R1.2 H4) — layout-stable loading shell for every
|
||||
* `next/dynamic` chart import on the dashboard and the insights
|
||||
* sub-pages.
|
||||
*
|
||||
* The chart components (`<HealthChart>`, `<MoodChart>`, …) live behind
|
||||
* `dynamic(() => import("…"), { ssr: false })`. Pre-fix, the loading
|
||||
* slot was empty: the page hydrated, the Recharts chunk fetched, and
|
||||
* the layout collapsed/expanded as the chart arrived. On a cold visit
|
||||
* over a slow network the gap was visible for several seconds (R1.2
|
||||
* H4).
|
||||
*
|
||||
* This skeleton mirrors the same container that `health-chart.tsx`
|
||||
* paints (rounded card, border, `p-4 md:p-6`) plus a faux header row
|
||||
* (title + range tabs) and a chart band sized to the CSS variable the
|
||||
* chart itself reads (`--chart-height` → 240 px mobile / 280 px md+).
|
||||
* The cumulative box matches the loaded chart's height to within a
|
||||
* pixel so the page does not jump on hydration.
|
||||
*
|
||||
* `prefers-reduced-motion` is honoured automatically — the `<Skeleton>`
|
||||
* primitive's `animate-pulse` is suppressed via Tailwind's
|
||||
* `motion-reduce:animate-none` modifier.
|
||||
*/
|
||||
export function ChartSkeleton({ className }: { className?: string }) {
|
||||
return (
|
||||
<div
|
||||
data-slot="chart-skeleton"
|
||||
role="status"
|
||||
aria-busy="true"
|
||||
aria-live="polite"
|
||||
className={cn(
|
||||
"bg-card border-border rounded-xl border p-4 md:p-6",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<span className="sr-only">Loading chart…</span>
|
||||
|
||||
{/* Header row — title + range tabs match the real chart's
|
||||
`mb-4 flex flex-col gap-2 sm:flex-row` chrome. */}
|
||||
<div className="mb-4 flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
|
||||
<Skeleton className="h-4 w-32" />
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="h-6 w-12" />
|
||||
<Skeleton className="h-6 w-12" />
|
||||
<Skeleton className="h-6 w-12" />
|
||||
<Skeleton className="h-6 w-12" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Chart band — mirrors the same `h-[var(--chart-height,…)]`
|
||||
contract `health-chart.tsx` paints at line 1087-1089. */}
|
||||
<Skeleton className="h-[var(--chart-height,240px)] w-full md:h-[var(--chart-height-md,280px)]" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import { ChartSkeleton } from "@/components/charts/chart-skeleton";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import type { ComparisonBaseline } from "@/lib/dashboard-layout";
|
||||
|
||||
@@ -26,7 +27,7 @@ const HealthChart = dynamic(
|
||||
import("@/components/charts/health-chart").then((mod) => ({
|
||||
default: mod.HealthChart,
|
||||
})),
|
||||
{ ssr: false },
|
||||
{ ssr: false, loading: () => <ChartSkeleton /> },
|
||||
);
|
||||
|
||||
export interface SleepDurationChartProps {
|
||||
|
||||
Reference in new issue
Block a user